Skip to content
This repository has been archived by the owner on Mar 8, 2019. It is now read-only.

Commit

Permalink
fix: multiple exports (#88)
Browse files Browse the repository at this point in the history
* make structure for exports

* make sure all exported members are named

* ready for muti mixins experimentation

* add multi mixins tests

* fix case of unit test

fixes #87
  • Loading branch information
elevatebart committed Jan 28, 2019
1 parent 619f22c commit ddfbf82
Show file tree
Hide file tree
Showing 24 changed files with 299 additions and 140 deletions.
26 changes: 16 additions & 10 deletions src/parse-script.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ParserPlugin } from '@babel/parser'
import * as bt from '@babel/types'
import { NodePath } from 'ast-types'
import Map from 'ts-map'
import buildParser from './babel-parser'
import { Documentation } from './Documentation'
import cacher from './utils/cacher'
Expand All @@ -11,13 +12,19 @@ import recast = require('recast')

const ERROR_MISSING_DEFINITION = 'No suitable component definition found'

interface ParseScriptOptions {
lang: 'ts' | 'js'
filePath: string
nameFilter?: string[]
}

export default function parseScript(
source: string,
documentation: Documentation,
handlers: Array<
(doc: Documentation, componentDefinition: NodePath, ast: bt.File, filePath: string) => void
>,
options: { lang: 'ts' | 'js'; filePath: string },
options: ParseScriptOptions,
) {
const plugins: ParserPlugin[] = options.lang === 'ts' ? ['typescript'] : ['flow']

Expand All @@ -26,28 +33,27 @@ export default function parseScript(
throw new Error(ERROR_MISSING_DEFINITION)
}

// FIXME: should be a Map<nameOfExport,NodePath>
// then the documentation can become a map itself and we can look at component/mixins
// with multiple items inside
const componentDefinitions = resolveExportedComponent(ast)

if (componentDefinitions.length === 0) {
if (componentDefinitions.size === 0) {
throw new Error(ERROR_MISSING_DEFINITION)
}

executeHandlers(handlers, componentDefinitions, documentation, ast, options.filePath)
executeHandlers(handlers, componentDefinitions, documentation, ast, options)
}

function executeHandlers(
localHandlers: Array<
(doc: Documentation, componentDefinition: NodePath, ast: bt.File, filePath: string) => void
>,
componentDefinitions: NodePath[],
componentDefinitions: Map<string, NodePath>,
documentation: Documentation,
ast: bt.File,
filePath: string,
opt: ParseScriptOptions,
) {
return componentDefinitions.forEach(compDef => {
localHandlers.forEach(handler => handler(documentation, compDef, ast, filePath))
return componentDefinitions.forEach((compDef, name) => {
if (compDef && name && (!opt.nameFilter || opt.nameFilter.indexOf(name) > -1)) {
localHandlers.forEach(handler => handler(documentation, compDef, ast, opt.filePath))
}
})
}
13 changes: 9 additions & 4 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ const ERROR_EMPTY_DOCUMENT = 'The passed source is empty'
* @param {string} filePath path of the current file against whom to resolve the mixins
* @returns {object} documentation object
*/
export function parseFile(filePath: string, documentation: Documentation) {
export function parseFile(filePath: string, documentation: Documentation, nameFilter?: string[]) {
const source = fs.readFileSync(filePath, {
encoding: 'utf-8',
})
return parseSource(source, filePath, documentation)
return parseSource(source, filePath, documentation, nameFilter)
}

/**
Expand All @@ -29,7 +29,12 @@ export function parseFile(filePath: string, documentation: Documentation) {
* @param {string} filePath path of the current file against whom to resolve the mixins
* @returns {object} documentation object
*/
export function parseSource(source: string, filePath: string, documentation: Documentation) {
export function parseSource(
source: string,
filePath: string,
documentation: Documentation,
nameFilter?: string[],
) {
const singleFileComponent = /\.vue$/i.test(path.extname(filePath))
let parts: SFCDescriptor | null = null

Expand All @@ -48,7 +53,7 @@ export function parseSource(source: string, filePath: string, documentation: Doc
/\.tsx?$/i.test(path.extname(filePath))
? 'ts'
: 'js'
parseScript(scriptSource, documentation, handlers, { lang, filePath })
parseScript(scriptSource, documentation, handlers, { lang, filePath, nameFilter })
}

// get slots from template
Expand Down
12 changes: 8 additions & 4 deletions src/script-handlers/__tests__/classDisplayNameHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ describe('classDisplayNameHandler', () => {
export default class Decorum extends Vue{
}
`
const def = parse(src)
classDisplayNameHandler(documentation, def[0])
const def = parse(src).get('default')
if (def) {
classDisplayNameHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('displayName', 'Decorum')
})

Expand All @@ -34,8 +36,10 @@ describe('classDisplayNameHandler', () => {
export default class Test extends Vue{
}
`
const def = parse(src)
classDisplayNameHandler(documentation, def[0])
const def = parse(src).get('default')
if (def) {
classDisplayNameHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('displayName', 'decorum')
})
})
10 changes: 7 additions & 3 deletions src/script-handlers/__tests__/classMethodHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { NodePath } from 'ast-types'
import Map from 'ts-map'
import babylon from '../../babel-parser'
import { Documentation, MethodDescriptor } from '../../Documentation'
import resolveExportedComponent from '../../utils/resolveExportedComponent'
import classMethodHandler from '../classMethodHandler'

jest.mock('../../Documentation')

function parseTS(src: string) {
function parseTS(src: string): Map<string, NodePath> {
const ast = babylon({ plugins: ['typescript'] }).parse(src)
return resolveExportedComponent(ast)
}
Expand All @@ -26,8 +28,10 @@ describe('classPropHandler', () => {
})

function tester(src: string, matchedObj: any) {
const def = parseTS(src)
classMethodHandler(documentation, def[0])
const def = parseTS(src).get('default')
if (def) {
classMethodHandler(documentation, def)
}
expect(mockMethodDescriptor).toMatchObject(matchedObj)
}

Expand Down
8 changes: 5 additions & 3 deletions src/script-handlers/__tests__/classPropHandler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { NodePath } from 'ast-types'
import Map from 'ts-map'
import babylon from '../../babel-parser'
import { Documentation, PropDescriptor } from '../../Documentation'
import resolveExportedComponent from '../../utils/resolveExportedComponent'
import classPropHandler from '../classPropHandler'

jest.mock('../../Documentation')

function parse(src: string) {
function parse(src: string): Map<string, NodePath> {
const ast = babylon({ plugins: ['typescript'] }).parse(src)
return resolveExportedComponent(ast)
}
Expand All @@ -27,8 +29,8 @@ describe('propHandler', () => {
})

function tester(src: string, matchedObj: any) {
const def = parse(src)
classPropHandler(documentation, def[0] as any)
const def = parse(src).get('default')
classPropHandler(documentation, def as any)
expect(mockPropDescriptor).toMatchObject(matchedObj)
}

Expand Down
22 changes: 15 additions & 7 deletions src/script-handlers/__tests__/componentHandler.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { ParserPlugin } from '@babel/parser'
import { NodePath } from 'ast-types'
import Map from 'ts-map'
import babylon from '../../babel-parser'
import { Documentation } from '../../Documentation'
import resolveExportedComponent from '../../utils/resolveExportedComponent'
import componentHandler from '../componentHandler'

jest.mock('../../Documentation')

function parse(src: string, plugins: ParserPlugin[] = []) {
function parse(src: string, plugins: ParserPlugin[] = []): Map<string, NodePath> {
const ast = babylon({ plugins }).parse(src)
return resolveExportedComponent(ast)
}
Expand All @@ -27,8 +29,10 @@ describe('componentHandler', () => {
name: 'name-123',
}
`
const def = parse(src)
componentHandler(documentation, def[0])
const def = parse(src).get('default')
if (def) {
componentHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('description', 'An empty component')
})

Expand All @@ -43,8 +47,10 @@ describe('componentHandler', () => {
name: 'name-123',
}
`
const def = parse(src)
componentHandler(documentation, def[0])
const def = parse(src).get('default')
if (def) {
componentHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('tags', {
author: [{ description: '[Rafael]', title: 'author' }],
version: [{ description: '12.5.7', title: 'version' }],
Expand All @@ -62,8 +68,10 @@ describe('componentHandler', () => {
}
`
const def = parse(src, ['typescript'])
componentHandler(documentation, def[0])
const def = parse(src, ['typescript']).get('default')
if (def) {
componentHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('tags', {
version: [{ description: '12.5.7', title: 'version' }],
})
Expand Down
13 changes: 9 additions & 4 deletions src/script-handlers/__tests__/displayNameHandler.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { NodePath } from 'ast-types'
import babylon from '../../babel-parser'
import { Documentation } from '../../Documentation'
import resolveExportedComponent from '../../utils/resolveExportedComponent'
import displayNameHandler from '../displayNameHandler'

jest.mock('../../Documentation')

function parse(src: string) {
function parse(src: string): NodePath | undefined {
const ast = babylon().parse(src)
return resolveExportedComponent(ast)
return resolveExportedComponent(ast).get('default')
}

describe('displayNameHandler', () => {
Expand All @@ -27,7 +28,9 @@ describe('displayNameHandler', () => {
}
`
const def = parse(src)
displayNameHandler(documentation, def[0])
if (def) {
displayNameHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('displayName', 'name-123')
})

Expand All @@ -42,7 +45,9 @@ describe('displayNameHandler', () => {
}
`
const def = parse(src)
displayNameHandler(documentation, def[0])
if (def) {
displayNameHandler(documentation, def)
}
expect(documentation.set).toHaveBeenCalledWith('displayName', 'name-123')
})
})
12 changes: 8 additions & 4 deletions src/script-handlers/__tests__/eventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import eventHandler from '../eventHandler'

jest.mock('../../Documentation')

function parse(src: string): NodePath[] {
function parse(src: string): NodePath | undefined {
const ast = babylon().parse(src)
return resolveExportedComponent(ast)
return resolveExportedComponent(ast).get('default')
}

describe('eventHandler', () => {
Expand Down Expand Up @@ -38,7 +38,9 @@ describe('eventHandler', () => {
}
`
const def = parse(src)
eventHandler(documentation, def[0])
if (def) {
eventHandler(documentation, def)
}
const eventComp: EventDescriptor = {
description: 'Describe the event',
properties: [
Expand Down Expand Up @@ -71,7 +73,9 @@ describe('eventHandler', () => {
}
`
const def = parse(src)
eventHandler(documentation, def[0])
if (def) {
eventHandler(documentation, def)
}
const eventComp: EventDescriptor = {
description: '',
type: {
Expand Down
23 changes: 14 additions & 9 deletions src/script-handlers/__tests__/extendsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ describe('extendsHandler', () => {
resolveRequiredMock = resolveRequired as jest.Mock<
(ast: bt.File, varNameFilter?: string[]) => { [key: string]: string }
>
resolveRequiredMock.mockReturnValue({ testComponent: './componentPath' })
resolveRequiredMock.mockReturnValue({
testComponent: { filePath: './componentPath', exportName: 'default' },
})

mockResolvePathFrom = resolvePathFrom as jest.Mock<(path: string, from: string) => string>
mockResolvePathFrom.mockReturnValue('./component/full/path')
Expand All @@ -30,8 +32,10 @@ describe('extendsHandler', () => {

function parseItExtends(src: string) {
const ast = babylon().parse(src)
const path = resolveExportedComponent(ast)
extendsHandler(doc, path[0], ast, '')
const path = resolveExportedComponent(ast).get('default')
if (path) {
extendsHandler(doc, path, ast, '')
}
}

it('should resolve extended modules variables in import default', () => {
Expand All @@ -42,7 +46,7 @@ describe('extendsHandler', () => {
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
})

it('should resolve extended modules variables in require', () => {
Expand All @@ -53,27 +57,28 @@ describe('extendsHandler', () => {
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
})

it('should resolve extended modules variables in import', () => {
const src = [
'import { testComponent, other } from "./testComponent"',
'import { test as testComponent, other } from "./testComponent"',
'export default {',
' extends:testComponent',
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
})

it('should resolve extended modules variables in class style components', () => {
const src = [
'import { testComponent} from "./testComponent"',
'import { testComponent } from "./testComponent";',
'@Component',
'export default class Bart extends testComponent {',
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
})
})

0 comments on commit ddfbf82

Please sign in to comment.