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

Commit

Permalink
fix: webpack alias (#91)
Browse files Browse the repository at this point in the history
* add alias parameter to ParseOptions
* add it to the main
* create the alias resolver
* resove components using aliases
* add e2e testing

closes #89
  • Loading branch information
elevatebart committed Jan 28, 2019
1 parent ddfbf82 commit 14ad5f5
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 58 deletions.
12 changes: 8 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import { parseFile, parseSource as parseSourceLocal } from './parse'

export { ComponentDoc }

export function parse(filePath: string): ComponentDoc {
export function parse(filePath: string, aliases?: { [alias: string]: string }): ComponentDoc {
const doc = new Documentation()
parseFile(filePath, doc)
parseFile(doc, { filePath, aliases })
return doc.toObject()
}

export function parseSource(source: string, filePath: string): ComponentDoc {
export function parseSource(
source: string,
filePath: string,
aliases?: { [alias: string]: string },
): ComponentDoc {
const doc = new Documentation()
parseSourceLocal(source, filePath, doc)
parseSourceLocal(doc, source, { filePath, aliases })
return doc.toObject()
}
26 changes: 12 additions & 14 deletions src/parse-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ import resolveExportedComponent from './utils/resolveExportedComponent'

// tslint:disable-next-line:no-var-requires
import recast = require('recast')
import { ParseOptions } from './parse'

const ERROR_MISSING_DEFINITION = 'No suitable component definition found'

interface ParseScriptOptions {
lang: 'ts' | 'js'
filePath: string
nameFilter?: string[]
}
type Handler = (
doc: Documentation,
componentDefinition: NodePath,
ast: bt.File,
opt: ParseOptions,
) => void

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

Expand All @@ -43,17 +43,15 @@ export default function parseScript(
}

function executeHandlers(
localHandlers: Array<
(doc: Documentation, componentDefinition: NodePath, ast: bt.File, filePath: string) => void
>,
localHandlers: Handler[],
componentDefinitions: Map<string, NodePath>,
documentation: Documentation,
ast: bt.File,
opt: ParseScriptOptions,
opt: ParseOptions,
) {
return componentDefinitions.forEach((compDef, name) => {
if (compDef && name && (!opt.nameFilter || opt.nameFilter.indexOf(name) > -1)) {
localHandlers.forEach(handler => handler(documentation, compDef, ast, opt.filePath))
localHandlers.forEach(handler => handler(documentation, compDef, ast, opt))
}
})
}
33 changes: 18 additions & 15 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@ import cacher from './utils/cacher'

const ERROR_EMPTY_DOCUMENT = 'The passed source is empty'

export interface ParseOptions {
filePath: string
lang?: 'ts' | 'js'
nameFilter?: string[]
aliases?: { [alias: string]: string }
}

/**
* parses the source and returns the doc
* @param {string} source code whose documentation is parsed
* @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, nameFilter?: string[]) {
const source = fs.readFileSync(filePath, {
export function parseFile(documentation: Documentation, opt: ParseOptions) {
const source = fs.readFileSync(opt.filePath, {
encoding: 'utf-8',
})
return parseSource(source, filePath, documentation, nameFilter)
return parseSource(documentation, source, opt)
}

/**
Expand All @@ -29,13 +36,8 @@ export function parseFile(filePath: string, documentation: Documentation, nameFi
* @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,
nameFilter?: string[],
) {
const singleFileComponent = /\.vue$/i.test(path.extname(filePath))
export function parseSource(documentation: Documentation, source: string, opt: ParseOptions) {
const singleFileComponent = /\.vue$/i.test(path.extname(opt.filePath))
let parts: SFCDescriptor | null = null

if (source === '') {
Expand All @@ -48,21 +50,22 @@ export function parseSource(

const scriptSource = parts ? (parts.script ? parts.script.content : undefined) : source
if (scriptSource) {
const lang =
opt.lang =
(parts && parts.script && parts.script.attrs && parts.script.attrs.lang === 'ts') ||
/\.tsx?$/i.test(path.extname(filePath))
/\.tsx?$/i.test(path.extname(opt.filePath))
? 'ts'
: 'js'
parseScript(scriptSource, documentation, handlers, { lang, filePath, nameFilter })

parseScript(scriptSource, documentation, handlers, opt)
}

// get slots from template
if (parts && parts.template) {
parseTemplate(parts.template, documentation, templateHandlers, filePath)
parseTemplate(parts.template, documentation, templateHandlers, opt.filePath)
}

if (!documentation.get('displayName')) {
// a component should always have a display name
documentation.set('displayName', path.basename(filePath).replace(/\.\w+$/, ''))
documentation.set('displayName', path.basename(opt.filePath).replace(/\.\w+$/, ''))
}
}
22 changes: 17 additions & 5 deletions src/script-handlers/__tests__/extendsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('extendsHandler', () => {
const ast = babylon().parse(src)
const path = resolveExportedComponent(ast).get('default')
if (path) {
extendsHandler(doc, path, ast, '')
extendsHandler(doc, path, ast, { filePath: '' })
}
}

Expand All @@ -46,7 +46,10 @@ describe('extendsHandler', () => {
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
expect(parseFile).toHaveBeenCalledWith(doc, {
filePath: './component/full/path',
nameFilter: ['default'],
})
})

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

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

it('should resolve extended modules variables in class style components', () => {
Expand All @@ -79,6 +88,9 @@ describe('extendsHandler', () => {
'}',
].join('\n')
parseItExtends(src)
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
expect(parseFile).toHaveBeenCalledWith(doc, {
filePath: './component/full/path',
nameFilter: ['default'],
})
})
})
9 changes: 6 additions & 3 deletions src/script-handlers/__tests__/mixinsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('mixinsHandler', () => {
})

mockResolvePathFrom = resolvePathFrom as jest.Mock<(path: string, from: string) => string>
mockResolvePathFrom.mockReturnValue('component/full/path')
mockResolvePathFrom.mockReturnValue('./component/full/path')

mockParse = parseFile as jest.Mock
mockParse.mockReturnValue({ component: 'documentation' })
Expand Down Expand Up @@ -53,8 +53,11 @@ describe('mixinsHandler', () => {
const ast = babelParser().parse(src)
const path = resolveExportedComponent(ast).get('default')
if (path) {
mixinsHandler(doc, path, ast, '')
mixinsHandler(doc, path, ast, { filePath: '' })
}
expect(parseFile).toHaveBeenCalledWith('component/full/path', doc, ['default'])
expect(parseFile).toHaveBeenCalledWith(doc, {
filePath: './component/full/path',
nameFilter: ['default'],
})
})
})
16 changes: 11 additions & 5 deletions src/script-handlers/extendsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as bt from '@babel/types'
import { NodePath } from 'ast-types'
import * as path from 'path'
import { Documentation } from '../Documentation'
import { parseFile } from '../parse'
import { parseFile, ParseOptions } from '../parse'
import resolveAliases from '../utils/resolveAliases'
import resolvePathFrom from '../utils/resolvePathFrom'
import resolveRequired from '../utils/resolveRequired'

Expand All @@ -16,7 +17,7 @@ export default function extendsHandler(
documentation: Documentation,
componentDefinition: NodePath,
astPath: bt.File,
originalFilePath: string,
opt: ParseOptions,
) {
const extendsVariableName = getExtendsVariableName(componentDefinition)

Expand All @@ -28,15 +29,20 @@ export default function extendsHandler(
// get all require / import statements
const extendsFilePath = resolveRequired(astPath, [extendsVariableName])

const originalDirName = path.dirname(originalFilePath)
const originalDirName = path.dirname(opt.filePath)

// only look for documentation in the current project not in node_modules
if (/^\./.test(extendsFilePath[extendsVariableName].filePath)) {
const fullFilePath = resolvePathFrom(
extendsFilePath[extendsVariableName].filePath,
resolveAliases(extendsFilePath[extendsVariableName].filePath, opt.aliases || {}),
originalDirName,
)
parseFile(fullFilePath, documentation, [extendsFilePath[extendsVariableName].exportName])

parseFile(documentation, {
...opt,
filePath: fullFilePath,
nameFilter: [extendsFilePath[extendsVariableName].exportName],
})
}
}

Expand Down
26 changes: 20 additions & 6 deletions src/script-handlers/mixinsHandler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as bt from '@babel/types'
import { NodePath } from 'ast-types'
import * as path from 'path'
import Map from 'ts-map'
import { Documentation } from '../Documentation'
import { parseFile } from '../parse'
import { parseFile, ParseOptions } from '../parse'
import resolveAliases from '../utils/resolveAliases'
import resolvePathFrom from '../utils/resolvePathFrom'
import resolveRequired from '../utils/resolveRequired'

Expand All @@ -15,9 +17,10 @@ export default function mixinsHandler(
documentation: Documentation,
componentDefinition: NodePath,
astPath: bt.File,
originalFilePath: string,
opt: ParseOptions,
) {
const originalDirName = path.dirname(originalFilePath)
const originalDirName = path.dirname(opt.filePath)

// filter only mixins
const mixinVariableNames = getMixinsVariableNames(componentDefinition)

Expand All @@ -29,12 +32,23 @@ export default function mixinsHandler(
const mixinVarToFilePath = resolveRequired(astPath, mixinVariableNames)

// get each doc for each mixin using parse
const files = new Map<string, string[]>()
for (const varName of Object.keys(mixinVarToFilePath)) {
// TODO: consolidate variables accessing the same file
const { filePath, exportName } = mixinVarToFilePath[varName]
const fullFilePath = resolvePathFrom(filePath, originalDirName)
parseFile(fullFilePath, documentation, [exportName])
const fullFilePath = resolvePathFrom(
resolveAliases(filePath, opt.aliases || {}),
originalDirName,
)
const vars = files.get(fullFilePath) || []
vars.push(exportName)
files.set(fullFilePath, vars)
}

files.forEach((vars, fullFilePath) => {
if (fullFilePath && vars) {
parseFile(documentation, { ...opt, filePath: fullFilePath, nameFilter: vars })
}
})
}

function getMixinsVariableNames(compDef: NodePath): string[] | undefined {
Expand Down
12 changes: 12 additions & 0 deletions src/utils/__tests__/resolveAliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as path from 'path'
import resolveAliases from '../resolveAliases'

describe('resolveAliases', () => {
it('should resolve aliased from a path', () => {
expect(
resolveAliases('myPath/somethingNice/mixinFile.js', {
myPath: './replacementPath/src/mixins',
}),
).toEqual(path.join('./replacementPath/src/mixins', 'somethingNice/mixinFile.js'))
})
})
20 changes: 20 additions & 0 deletions src/utils/resolveAliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as path from 'path'

export default function resolveAliases(
filePath: string,
aliases: { [alias: string]: string },
): string {
const aliasKeys = Object.keys(aliases)
let i = aliasKeys.length
let aliasFound = false
if (!aliasKeys.length) {
return filePath
}
while (!aliasFound && i--) {
aliasFound = filePath.substring(0, aliasKeys[i].length) === aliasKeys[i]
}
if (!aliasFound) {
return filePath
}
return path.join(aliases[aliasKeys[i]], filePath.substring(aliasKeys[i].length + 1))
}
10 changes: 5 additions & 5 deletions tests/components/button/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
<script>
import Vue from 'vue'
import { ClientTable } from 'some-plugin'
import another from '../../mixins/another'
import anotherMixin from '../../mixins/anotherMixin'
import model from '../../utils/model.json'
import another from '@mixins/another'
import anotherMixin from '@utils/anotherMixin'
import model from '@utils/model.json'
import genericMixin from './genericMixin'
import colorMixin from './colorMixin'
import review from '../../utils/review.json'
import { multi, hidden } from '../../mixins/multiMixin'
import review from '@utils/review.json'
import { multi, hidden } from '@mixins/multiMixin'
Vue.use(ClientTable)
Expand Down
5 changes: 4 additions & 1 deletion tests/components/button/button.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ let docButton: ComponentDoc

describe('tests button', () => {
beforeAll(done => {
docButton = parse(button)
docButton = parse(button, {
'@mixins': path.resolve(__dirname, '../../mixins'),
'@utils': path.resolve(__dirname, '../../utils'),
})
done()
})

Expand Down

0 comments on commit 14ad5f5

Please sign in to comment.