Skip to content

Commit

Permalink
(docz-core) handle props on windows (#1151)
Browse files Browse the repository at this point in the history
* fix(docz-core): test for setting props on

* fix(docz-core): use unix path for keys and fast glob

* fix(docz-core): normalize and use unix path on keys in props parser

* chore(docz-core): move test helpers out of test folder

* chore(e2e-tests): add test for checking props

* fix(docz-core): use regular path in filesmap and update e2e test
  • Loading branch information
Jesper Orb authored and rakannimer committed Oct 6, 2019
1 parent 6348cb9 commit ee71ef8
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 24 deletions.
28 changes: 28 additions & 0 deletions core/docz-core/__fixtures__/Alert/Alert.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: Alert
menu: Components
---

import { Playground, Props } from 'docz'
import { Alert } from './Alert'

# Alert

## Properties

<Props of={Alert} />

## Basic usage

<Playground>
<Alert>Some message</Alert>
</Playground>

## Using different kinds

<Playground>
<Alert kind="info">Some message</Alert>
<Alert kind="positive">Some message</Alert>
<Alert kind="negative">Some message</Alert>
<Alert kind="warning">Some message</Alert>
</Playground>
32 changes: 32 additions & 0 deletions core/docz-core/__fixtures__/Alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { SFC } from 'react'
import styled from '@emotion/styled'

export type Kind = 'info' | 'positive' | 'negative' | 'warning'
export type KindMap = Record<Kind, string>

const kinds: KindMap = {
info: '#5352ED',
positive: '#2ED573',
negative: '#FF4757',
warning: '#FFA502',
}

export interface AlertProps {
/**
* Set this to change alert kind
* @default info
*/
kind: 'info' | 'positive' | 'negative' | 'warning'
}

const AlertStyled = styled('div')<AlertProps>`
padding: 15px 20px;
background: white;
border-radius: 3px;
color: white;
background: ${({ kind = 'info' }) => kinds[kind]};
`

export const Alert: SFC<AlertProps> = ({ kind, ...props }) => (
<AlertStyled {...props} kind={kind} />
)
15 changes: 15 additions & 0 deletions core/docz-core/__fixtures__/Label.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import t from 'prop-types'

const Label = ({ text, ...props }) => (
<div className="label" {...props}>
{text}
</div>
)

Label.propTypes = {
/** A nice string */
text: t.string,
}

export default Label
17 changes: 17 additions & 0 deletions core/docz-core/__fixtures__/Label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { SFC } from 'react'

export interface LabelProps {
/**
* Set this to do the thing
* @default info
*/
text: string
}

const Label: SFC<LabelProps> = ({ text, ...props }) => (
<div className="label" {...props}>
{text}
</div>
)

export default Label
10 changes: 10 additions & 0 deletions core/docz-core/__tests__/entries.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Entries } from '../src/lib/Entries'
import { getTestConfig } from '../src/test-utils'

describe('Entries', () => {
test('get entries', async () => {
const config = getTestConfig()
const entries = new Entries(config)
expect(entries).toBeTruthy()
})
})
86 changes: 86 additions & 0 deletions core/docz-core/__tests__/props.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import * as fs from 'fs-extra'
import { getPattern, initial } from '../src/states/props'
import { readCacheFile } from '../src/utils/docgen/typescript'
import { getTestConfig, mockedParams } from '../src/test-utils'

describe('props', () => {
beforeEach(() => {
if (fs.existsSync('./.docz/.cache/propsParser.json')) {
fs.unlinkSync('./.docz/.cache/propsParser.json')
}
})

describe('typescript', () => {
test('should set props from typescript files', async () => {
const config = getTestConfig()
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
expect(params.getState().props.length).toBeGreaterThan(0)
})

test('should set correct key on parsed typescript files', async () => {
const config = getTestConfig()
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
const expectedFirstPropName = '__fixtures__/Label.tsx'
const firstProp = params.getState().props[0]
expect(firstProp.key).toEqual(expectedFirstPropName)
expect(firstProp.value).toBeTruthy()
})
})

describe('javascript', () => {
test('should set correct key on parsed javascript files', async () => {
const config = getTestConfig({ typescript: undefined })
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
const expectedFirstPropName = '__fixtures__/Label.jsx'
const firstProp = params.getState().props[0]
expect(firstProp.key).toEqual(expectedFirstPropName)
expect(firstProp.value).toBeTruthy()
})

test('should set props from javascript files', async () => {
const config = getTestConfig({ typescript: undefined })
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
expect(params.getState().props.length).toBeGreaterThan(0)
})

test('should have props on javascript files', async () => {
const config = getTestConfig({ typescript: undefined })
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
const firstProp = params.getState().props[0]
expect(firstProp.value[0].props).toBeTruthy()
})
})

describe('cache', () => {
test('should have empty cache on start', async () => {
const cache = readCacheFile()
expect(cache).toBeNull()
})

test('should set cache on loading props', async () => {
const cache = readCacheFile()
expect(cache).toBeNull()
const config = getTestConfig()
const pattern = getPattern(config)
const data = initial(config, pattern)
const params = mockedParams()
await data(params)
expect(readCacheFile()).not.toBeNull()
})
})
})
16 changes: 11 additions & 5 deletions core/docz-core/src/states/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { get, propEq } from 'lodash/fp'

import * as paths from '../config/paths'
import { Config } from '../config/argv'
import { docgen } from '../utils/docgen'
import { docgen, unixPath } from '../utils/docgen'
import { WATCH_IGNORE } from './config'

const getPattern = (config: Config) => {
export const getPattern = (config: Config) => {
const {
ignore,
src: source,
Expand All @@ -21,12 +21,16 @@ const getPattern = (config: Config) => {
const root = paths.getRootDir(config)
const srcDir = path.resolve(root, searchPath)
const src = path.relative(root, srcDir)
const filesPattern = path.join(
src,
ts ? '**/*.{ts,tsx,js,jsx,mjs}' : '**/*.{js,jsx,mjs}'
)

return ignore
.map(entry => typeof entry === 'string' && `!**/${entry}`)
.filter(Boolean)
.concat([
path.join(src, ts ? '**/*.{ts,tsx,js,jsx,mjs}' : '**/*.{js,jsx,mjs}'),
unixPath(filesPattern),
'!**/node_modules',
'!**/doczrc.js',
]) as string[]
Expand All @@ -35,10 +39,12 @@ const getPattern = (config: Config) => {
const removeFilepath = (items: any[], filepath: string) =>
items.filter((item: any) => item.key !== filepath)

const initial = (config: Config, pattern: string[]) => async (p: Params) => {
export const initial = (config: Config, pattern: string[]) => async (
p: Params
) => {
const { filterComponents } = config
const cwd = paths.getRootDir(config)
const files = await fastglob(pattern, { cwd })
const files = await fastglob(pattern, { cwd, caseSensitiveMatch: false })
const filtered = filterComponents ? filterComponents(files) : files
const metadata = await docgen(filtered, config)
p.setState('props', metadata)
Expand Down
38 changes: 38 additions & 0 deletions core/docz-core/src/test-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as paths from '../config/paths'
import yargs from 'yargs'
import { setArgs, Config } from '../config/argv'
import { Params } from '../lib/DataServer'
import { getBaseConfig } from '../config/docz'

export const mockedParams = (): Params => {
let data: any = {}
return {
getState: () => data,
setState: (key: string, value: string) => (data[key] = value),
}
}

export const mockedArgv = () => {
const yargsArgs: any = {
argv: {},
//@ts-ignore
option: jest.fn().mockImplementation((key, value) => {
yargs.argv[value.alias ? value.alias : key] = value.default
return yargs
}),
}
const { argv } = setArgs(yargsArgs)
return argv
}

export const getTestConfig = (overrides?: Partial<Config>): Config => {
const argv = mockedArgv()
return {
//@ts-ignore
...getBaseConfig(argv),
paths,
typescript: true,
src: './__fixtures__',
...overrides,
}
}
5 changes: 5 additions & 0 deletions core/docz-core/src/utils/docgen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import * as paths from '../../config/paths'
import { Config } from '../../config/argv'
import { jsParser } from './javascript'
import { tsParser } from './typescript'
import { normalize } from 'path'

export const unixPath = (src: string): string => {
return normalize(src).replace(/\\/g, '/')
}

export const docgen = async (files: string[], config: Config) => {
const cwd = paths.getRootDir(config)
Expand Down
5 changes: 3 additions & 2 deletions core/docz-core/src/utils/docgen/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import * as path from 'path'
import logger from 'signale'
import externalProptypesHandler from './externalProptypesHandler'
import actualNameHandler from 'react-docgen-actual-name-handler'
import reactDocgen from 'react-docgen'
import * as reactDocgen from 'react-docgen'

import { Config } from '../../config/argv'
import { getRootDir } from '../../config/paths'
import { unixPath } from '.'

const throwError = (err: any) => {
logger.fatal(`Error parsing static types`)
Expand All @@ -29,7 +30,7 @@ export const jsParser = (files: string[], config: Config) => {
try {
const code = fs.readFileSync(fullpath, { encoding: 'utf-8' })
const props = reactDocgen.parse(code, resolver, handlers)
return { key: path.normalize(filepath), value: props }
return { key: unixPath(filepath), value: props }
} catch (err) {
if (config.debug) throwError(err)
return null
Expand Down
15 changes: 8 additions & 7 deletions core/docz-core/src/utils/docgen/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import * as path from 'path'
import * as crypto from 'crypto'
import * as _ from 'lodash/fp'
import * as logger from 'signale'
import reactDocgenTs from 'react-docgen-typescript'
import * as reactDocgenTs from 'react-docgen-typescript'
import ts from 'typescript'

import { Config } from '../../config/argv'
import * as paths from '../../config/paths'
import { unixPath } from '.'

export interface TSFile {
text?: string
Expand All @@ -26,7 +27,8 @@ const digest = (str: string) =>
.digest('hex')

const cacheFilepath = path.join(paths.cache, 'propsParser.json')
const readCacheFile = () => fs.readJSONSync(cacheFilepath, { throws: false })
export const readCacheFile = () =>
fs.readJSONSync(cacheFilepath, { throws: false })

function checkFilesOnCache(files: string[], config: Config): string[] {
const cache = readCacheFile()
Expand All @@ -45,10 +47,9 @@ function writePropsOnCache(items: PropItem[], config: Config): void {
const cache = readCacheFile()
const root = paths.getRootDir(config)
const newCache = items.reduce((obj, { key: filepath, value }) => {
const normalized = path.normalize(filepath)
const fullpath = path.resolve(root, normalized)
const fullpath = path.resolve(root, path.normalize(filepath))
const hash = digest(fs.readFileSync(fullpath, 'utf-8'))
return { ...obj, [normalized]: { hash, props: value } }
return { ...obj, [unixPath(filepath)]: { hash, props: value } }
}, {})

fs.outputJSONSync(cacheFilepath, { ...cache, ...newCache })
Expand All @@ -64,7 +65,7 @@ function getPropsOnCache(): any {
}

return Object.entries(cache).map(([key, value]) => ({
key,
key: unixPath(key),
value: _.get('props', value),
}))
}
Expand Down Expand Up @@ -195,7 +196,7 @@ const parseFiles = (files: string[], config: Config, tsconfig: string) => {
}

return files.map(filepath => ({
key: path.normalize(filepath),
key: unixPath(filepath),
value: parser.parseWithProgramProvider(filepath, programProvider),
}))
}
Expand Down
12 changes: 2 additions & 10 deletions examples/typescript/src/components/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { SFC } from 'react'
import styled from '@emotion/styled'

export type Kind = 'info' | 'positive' | 'negative' | 'warning'
export type KindMap = Record<Kind, string>
Expand All @@ -19,14 +18,7 @@ export interface AlertProps {
kind: 'info' | 'positive' | 'negative' | 'warning'
}

const AlertStyled = styled('div')<AlertProps>`
padding: 15px 20px;
background: white;
border-radius: 3px;
color: white;
background: ${({ kind = 'info' }) => kinds[kind]};
`

export const Alert: SFC<AlertProps> = ({ kind, ...props }) => (
<AlertStyled {...props} kind={kind} />
//@ts-ignore
<div className="alert"> </div>
)
Loading

0 comments on commit ee71ef8

Please sign in to comment.