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

Commit 14ad5f5

Browse files
authored
fix: webpack alias (#91)
* add alias parameter to ParseOptions * add it to the main * create the alias resolver * resove components using aliases * add e2e testing closes #89
1 parent ddfbf82 commit 14ad5f5

File tree

11 files changed

+133
-58
lines changed

11 files changed

+133
-58
lines changed

src/main.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ import { parseFile, parseSource as parseSourceLocal } from './parse'
33

44
export { ComponentDoc }
55

6-
export function parse(filePath: string): ComponentDoc {
6+
export function parse(filePath: string, aliases?: { [alias: string]: string }): ComponentDoc {
77
const doc = new Documentation()
8-
parseFile(filePath, doc)
8+
parseFile(doc, { filePath, aliases })
99
return doc.toObject()
1010
}
1111

12-
export function parseSource(source: string, filePath: string): ComponentDoc {
12+
export function parseSource(
13+
source: string,
14+
filePath: string,
15+
aliases?: { [alias: string]: string },
16+
): ComponentDoc {
1317
const doc = new Documentation()
14-
parseSourceLocal(source, filePath, doc)
18+
parseSourceLocal(doc, source, { filePath, aliases })
1519
return doc.toObject()
1620
}

src/parse-script.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,22 @@ import resolveExportedComponent from './utils/resolveExportedComponent'
99

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

1314
const ERROR_MISSING_DEFINITION = 'No suitable component definition found'
1415

15-
interface ParseScriptOptions {
16-
lang: 'ts' | 'js'
17-
filePath: string
18-
nameFilter?: string[]
19-
}
16+
type Handler = (
17+
doc: Documentation,
18+
componentDefinition: NodePath,
19+
ast: bt.File,
20+
opt: ParseOptions,
21+
) => void
2022

2123
export default function parseScript(
2224
source: string,
2325
documentation: Documentation,
24-
handlers: Array<
25-
(doc: Documentation, componentDefinition: NodePath, ast: bt.File, filePath: string) => void
26-
>,
27-
options: ParseScriptOptions,
26+
handlers: Handler[],
27+
options: ParseOptions,
2828
) {
2929
const plugins: ParserPlugin[] = options.lang === 'ts' ? ['typescript'] : ['flow']
3030

@@ -43,17 +43,15 @@ export default function parseScript(
4343
}
4444

4545
function executeHandlers(
46-
localHandlers: Array<
47-
(doc: Documentation, componentDefinition: NodePath, ast: bt.File, filePath: string) => void
48-
>,
46+
localHandlers: Handler[],
4947
componentDefinitions: Map<string, NodePath>,
5048
documentation: Documentation,
5149
ast: bt.File,
52-
opt: ParseScriptOptions,
50+
opt: ParseOptions,
5351
) {
5452
return componentDefinitions.forEach((compDef, name) => {
5553
if (compDef && name && (!opt.nameFilter || opt.nameFilter.indexOf(name) > -1)) {
56-
localHandlers.forEach(handler => handler(documentation, compDef, ast, opt.filePath))
54+
localHandlers.forEach(handler => handler(documentation, compDef, ast, opt))
5755
}
5856
})
5957
}

src/parse.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,24 @@ import cacher from './utils/cacher'
1010

1111
const ERROR_EMPTY_DOCUMENT = 'The passed source is empty'
1212

13+
export interface ParseOptions {
14+
filePath: string
15+
lang?: 'ts' | 'js'
16+
nameFilter?: string[]
17+
aliases?: { [alias: string]: string }
18+
}
19+
1320
/**
1421
* parses the source and returns the doc
1522
* @param {string} source code whose documentation is parsed
1623
* @param {string} filePath path of the current file against whom to resolve the mixins
1724
* @returns {object} documentation object
1825
*/
19-
export function parseFile(filePath: string, documentation: Documentation, nameFilter?: string[]) {
20-
const source = fs.readFileSync(filePath, {
26+
export function parseFile(documentation: Documentation, opt: ParseOptions) {
27+
const source = fs.readFileSync(opt.filePath, {
2128
encoding: 'utf-8',
2229
})
23-
return parseSource(source, filePath, documentation, nameFilter)
30+
return parseSource(documentation, source, opt)
2431
}
2532

2633
/**
@@ -29,13 +36,8 @@ export function parseFile(filePath: string, documentation: Documentation, nameFi
2936
* @param {string} filePath path of the current file against whom to resolve the mixins
3037
* @returns {object} documentation object
3138
*/
32-
export function parseSource(
33-
source: string,
34-
filePath: string,
35-
documentation: Documentation,
36-
nameFilter?: string[],
37-
) {
38-
const singleFileComponent = /\.vue$/i.test(path.extname(filePath))
39+
export function parseSource(documentation: Documentation, source: string, opt: ParseOptions) {
40+
const singleFileComponent = /\.vue$/i.test(path.extname(opt.filePath))
3941
let parts: SFCDescriptor | null = null
4042

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

4951
const scriptSource = parts ? (parts.script ? parts.script.content : undefined) : source
5052
if (scriptSource) {
51-
const lang =
53+
opt.lang =
5254
(parts && parts.script && parts.script.attrs && parts.script.attrs.lang === 'ts') ||
53-
/\.tsx?$/i.test(path.extname(filePath))
55+
/\.tsx?$/i.test(path.extname(opt.filePath))
5456
? 'ts'
5557
: 'js'
56-
parseScript(scriptSource, documentation, handlers, { lang, filePath, nameFilter })
58+
59+
parseScript(scriptSource, documentation, handlers, opt)
5760
}
5861

5962
// get slots from template
6063
if (parts && parts.template) {
61-
parseTemplate(parts.template, documentation, templateHandlers, filePath)
64+
parseTemplate(parts.template, documentation, templateHandlers, opt.filePath)
6265
}
6366

6467
if (!documentation.get('displayName')) {
6568
// a component should always have a display name
66-
documentation.set('displayName', path.basename(filePath).replace(/\.\w+$/, ''))
69+
documentation.set('displayName', path.basename(opt.filePath).replace(/\.\w+$/, ''))
6770
}
6871
}

src/script-handlers/__tests__/extendsHandler.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('extendsHandler', () => {
3434
const ast = babylon().parse(src)
3535
const path = resolveExportedComponent(ast).get('default')
3636
if (path) {
37-
extendsHandler(doc, path, ast, '')
37+
extendsHandler(doc, path, ast, { filePath: '' })
3838
}
3939
}
4040

@@ -46,7 +46,10 @@ describe('extendsHandler', () => {
4646
'}',
4747
].join('\n')
4848
parseItExtends(src)
49-
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
49+
expect(parseFile).toHaveBeenCalledWith(doc, {
50+
filePath: './component/full/path',
51+
nameFilter: ['default'],
52+
})
5053
})
5154

5255
it('should resolve extended modules variables in require', () => {
@@ -57,7 +60,10 @@ describe('extendsHandler', () => {
5760
'}',
5861
].join('\n')
5962
parseItExtends(src)
60-
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
63+
expect(parseFile).toHaveBeenCalledWith(doc, {
64+
filePath: './component/full/path',
65+
nameFilter: ['default'],
66+
})
6167
})
6268

6369
it('should resolve extended modules variables in import', () => {
@@ -68,7 +74,10 @@ describe('extendsHandler', () => {
6874
'}',
6975
].join('\n')
7076
parseItExtends(src)
71-
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
77+
expect(parseFile).toHaveBeenCalledWith(doc, {
78+
filePath: './component/full/path',
79+
nameFilter: ['default'],
80+
})
7281
})
7382

7483
it('should resolve extended modules variables in class style components', () => {
@@ -79,6 +88,9 @@ describe('extendsHandler', () => {
7988
'}',
8089
].join('\n')
8190
parseItExtends(src)
82-
expect(parseFile).toHaveBeenCalledWith('./component/full/path', doc, ['default'])
91+
expect(parseFile).toHaveBeenCalledWith(doc, {
92+
filePath: './component/full/path',
93+
nameFilter: ['default'],
94+
})
8395
})
8496
})

src/script-handlers/__tests__/mixinsHandler.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('mixinsHandler', () => {
2424
})
2525

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

2929
mockParse = parseFile as jest.Mock
3030
mockParse.mockReturnValue({ component: 'documentation' })
@@ -53,8 +53,11 @@ describe('mixinsHandler', () => {
5353
const ast = babelParser().parse(src)
5454
const path = resolveExportedComponent(ast).get('default')
5555
if (path) {
56-
mixinsHandler(doc, path, ast, '')
56+
mixinsHandler(doc, path, ast, { filePath: '' })
5757
}
58-
expect(parseFile).toHaveBeenCalledWith('component/full/path', doc, ['default'])
58+
expect(parseFile).toHaveBeenCalledWith(doc, {
59+
filePath: './component/full/path',
60+
nameFilter: ['default'],
61+
})
5962
})
6063
})

src/script-handlers/extendsHandler.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as bt from '@babel/types'
22
import { NodePath } from 'ast-types'
33
import * as path from 'path'
44
import { Documentation } from '../Documentation'
5-
import { parseFile } from '../parse'
5+
import { parseFile, ParseOptions } from '../parse'
6+
import resolveAliases from '../utils/resolveAliases'
67
import resolvePathFrom from '../utils/resolvePathFrom'
78
import resolveRequired from '../utils/resolveRequired'
89

@@ -16,7 +17,7 @@ export default function extendsHandler(
1617
documentation: Documentation,
1718
componentDefinition: NodePath,
1819
astPath: bt.File,
19-
originalFilePath: string,
20+
opt: ParseOptions,
2021
) {
2122
const extendsVariableName = getExtendsVariableName(componentDefinition)
2223

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

31-
const originalDirName = path.dirname(originalFilePath)
32+
const originalDirName = path.dirname(opt.filePath)
3233

3334
// only look for documentation in the current project not in node_modules
3435
if (/^\./.test(extendsFilePath[extendsVariableName].filePath)) {
3536
const fullFilePath = resolvePathFrom(
36-
extendsFilePath[extendsVariableName].filePath,
37+
resolveAliases(extendsFilePath[extendsVariableName].filePath, opt.aliases || {}),
3738
originalDirName,
3839
)
39-
parseFile(fullFilePath, documentation, [extendsFilePath[extendsVariableName].exportName])
40+
41+
parseFile(documentation, {
42+
...opt,
43+
filePath: fullFilePath,
44+
nameFilter: [extendsFilePath[extendsVariableName].exportName],
45+
})
4046
}
4147
}
4248

src/script-handlers/mixinsHandler.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as bt from '@babel/types'
22
import { NodePath } from 'ast-types'
33
import * as path from 'path'
4+
import Map from 'ts-map'
45
import { Documentation } from '../Documentation'
5-
import { parseFile } from '../parse'
6+
import { parseFile, ParseOptions } from '../parse'
7+
import resolveAliases from '../utils/resolveAliases'
68
import resolvePathFrom from '../utils/resolvePathFrom'
79
import resolveRequired from '../utils/resolveRequired'
810

@@ -15,9 +17,10 @@ export default function mixinsHandler(
1517
documentation: Documentation,
1618
componentDefinition: NodePath,
1719
astPath: bt.File,
18-
originalFilePath: string,
20+
opt: ParseOptions,
1921
) {
20-
const originalDirName = path.dirname(originalFilePath)
22+
const originalDirName = path.dirname(opt.filePath)
23+
2124
// filter only mixins
2225
const mixinVariableNames = getMixinsVariableNames(componentDefinition)
2326

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

3134
// get each doc for each mixin using parse
35+
const files = new Map<string, string[]>()
3236
for (const varName of Object.keys(mixinVarToFilePath)) {
33-
// TODO: consolidate variables accessing the same file
3437
const { filePath, exportName } = mixinVarToFilePath[varName]
35-
const fullFilePath = resolvePathFrom(filePath, originalDirName)
36-
parseFile(fullFilePath, documentation, [exportName])
38+
const fullFilePath = resolvePathFrom(
39+
resolveAliases(filePath, opt.aliases || {}),
40+
originalDirName,
41+
)
42+
const vars = files.get(fullFilePath) || []
43+
vars.push(exportName)
44+
files.set(fullFilePath, vars)
3745
}
46+
47+
files.forEach((vars, fullFilePath) => {
48+
if (fullFilePath && vars) {
49+
parseFile(documentation, { ...opt, filePath: fullFilePath, nameFilter: vars })
50+
}
51+
})
3852
}
3953

4054
function getMixinsVariableNames(compDef: NodePath): string[] | undefined {

src/utils/__tests__/resolveAliases.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import * as path from 'path'
2+
import resolveAliases from '../resolveAliases'
3+
4+
describe('resolveAliases', () => {
5+
it('should resolve aliased from a path', () => {
6+
expect(
7+
resolveAliases('myPath/somethingNice/mixinFile.js', {
8+
myPath: './replacementPath/src/mixins',
9+
}),
10+
).toEqual(path.join('./replacementPath/src/mixins', 'somethingNice/mixinFile.js'))
11+
})
12+
})

src/utils/resolveAliases.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as path from 'path'
2+
3+
export default function resolveAliases(
4+
filePath: string,
5+
aliases: { [alias: string]: string },
6+
): string {
7+
const aliasKeys = Object.keys(aliases)
8+
let i = aliasKeys.length
9+
let aliasFound = false
10+
if (!aliasKeys.length) {
11+
return filePath
12+
}
13+
while (!aliasFound && i--) {
14+
aliasFound = filePath.substring(0, aliasKeys[i].length) === aliasKeys[i]
15+
}
16+
if (!aliasFound) {
17+
return filePath
18+
}
19+
return path.join(aliases[aliasKeys[i]], filePath.substring(aliasKeys[i].length + 1))
20+
}

tests/components/button/Button.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
<script>
99
import Vue from 'vue'
1010
import { ClientTable } from 'some-plugin'
11-
import another from '../../mixins/another'
12-
import anotherMixin from '../../mixins/anotherMixin'
13-
import model from '../../utils/model.json'
11+
import another from '@mixins/another'
12+
import anotherMixin from '@utils/anotherMixin'
13+
import model from '@utils/model.json'
1414
import genericMixin from './genericMixin'
1515
import colorMixin from './colorMixin'
16-
import review from '../../utils/review.json'
17-
import { multi, hidden } from '../../mixins/multiMixin'
16+
import review from '@utils/review.json'
17+
import { multi, hidden } from '@mixins/multiMixin'
1818
1919
Vue.use(ClientTable)
2020

tests/components/button/button.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ let docButton: ComponentDoc
77

88
describe('tests button', () => {
99
beforeAll(done => {
10-
docButton = parse(button)
10+
docButton = parse(button, {
11+
'@mixins': path.resolve(__dirname, '../../mixins'),
12+
'@utils': path.resolve(__dirname, '../../utils'),
13+
})
1114
done()
1215
})
1316

0 commit comments

Comments
 (0)