Skip to content

Commit

Permalink
refactor: separate fs dependency from core logic
Browse files Browse the repository at this point in the history
  • Loading branch information
solufa committed Jun 24, 2020
1 parent 1063cba commit 2842e61
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 50 deletions.
4 changes: 2 additions & 2 deletions packages/aspida/samples/$api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { Methods as Methods0 } from './index'
import { Methods as Methods1 } from './_sampleId.json@number'
import { Methods as Methods2 } from './v1.1'
import { Methods as Methods3 } from './v1.1/2/_hogeId@HogeId/entries.json'
import { Methods as Methods4 } from './v1.1/2/_hogeId@HogeId/test-4/index'
import { Methods as Methods4 } from './v1.1/2/_hogeId@HogeId/test-4'
import { Methods as Methods5 } from './v1.1/2/_hogeId@HogeId/test-4/_fugaId'
import { Methods as Methods6 } from './v1.1/2/_hogeId@HogeId/test-4/fuga aa'
import { Methods as Methods7 } from './v1.1/2/_hogeId@number'
import { Methods as Methods8 } from './v1.1/3.1'
import { Methods as Methods9 } from './v1.1/_articleId.json'
import { Methods as Methods10 } from './v1.1/users/_userId@User[\'id\']'
import { Methods as Methods11 } from './v2.0/index'
import { Methods as Methods11 } from './v2.0'

const api = <T>(client: AspidaClient<T>) => {
const prefix = (client.baseURL === undefined ? 'https://example.com/api/' : client.baseURL).replace(/\/$/, '')
Expand Down
3 changes: 2 additions & 1 deletion packages/aspida/src/buildTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import path from 'path'
import { BaseConfig } from './getConfig'
import createTemplateValues from './createTemplateValues'
import { getDirentTree } from './getDirentTree'

export type Template = {
text: string
filePath: string
}

export default ({ input, baseURL, trailingSlash }: BaseConfig): Template => {
const { api, imports } = createTemplateValues(input, trailingSlash)
const { api, imports } = createTemplateValues(getDirentTree(input), trailingSlash)
const text = `/* eslint-disable */
import { AspidaClient${api.includes('BasicHeaders') ? ', BasicHeaders' : ''} } from 'aspida'
<% types %><% imports %>
Expand Down
80 changes: 33 additions & 47 deletions packages/aspida/src/createTemplateValues.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
import fs from 'fs'
import path from 'path'
import createMethods from './createMethodsString'
import parseInterface from './parseInterface'
import { Method } from './parseInterface'
import { DirentTree } from './getDirentTree'

export default (input: string, trailingSlash: boolean) => {
export default (direntTree: DirentTree, trailingSlash: boolean) => {
const imports: string[] = []
const getMethodsString = (file: string, target: string, indent: string, newUrl: string) => {
const methodsInterface = parseInterface(fs.readFileSync(target, 'utf8'), 'Methods')
if (!methodsInterface) return ''

let importName = ''
if (methodsInterface.some(({ props }) => Object.keys(props).length)) {
importName = `Methods${imports.length}`
imports.push(`import { Methods as ${importName} } from '${file.replace(/'/g, "\\'")}'`)
}

return createMethods(methodsInterface, indent, importName, newUrl, trailingSlash)
const getMethodsString = (file: string, methods: Method[], indent: string, newUrl: string) => {
const importName = `Methods${imports.length}`
imports.push(`import { Methods as ${importName} } from '${file.replace(/'/g, "\\'")}'`)
return createMethods(methods, indent, importName, newUrl, trailingSlash)
}

let valCount = 0

const createApiString = (
targetDir: string,
tree: DirentTree,
importBasePath: string,
indent: string,
url: string,
text: string,
methodsOfIndexTsFile?: string
): string => {
indent += ' '

const props = fs
.readdirSync(targetDir)
.sort()
.map((file, _, dirList) => {
if (file.startsWith('$') || file.startsWith('@')) return

const props = tree.children
.map(dirent => {
const file = dirent.name
const basename = path.basename(file, '.ts')
let valFn = `${indent}${basename
.replace(/[^a-zA-Z0-9$_]/g, '_')
Expand All @@ -49,40 +37,39 @@ export default (input: string, trailingSlash: boolean) => {
valType = `ApiTypes.${valType}`
}

const duplicatedNames = dirList.filter(d => d.startsWith(valName))
const duplicatedNames = tree.children.filter(d => d.name.startsWith(valName))

valFn = `${indent}${valName.replace(/\./g, '_')}${
duplicatedNames.length > 1 ? `_${duplicatedNames.indexOf(file)}` : ''
duplicatedNames.length > 1 ? `_${duplicatedNames.indexOf(dirent)}` : ''
}: (val${valCount}: ${valType}) => ({\n<% next %>\n${indent}})`
newUrl = `${url}/\${val${valCount}}${valName.replace(/^[^.]+/, '')}`
valCount += 1
}

const target = path.posix.join(targetDir, file)

if (fs.statSync(target).isDirectory()) {
const indexPath = path.posix.join(target, 'index.ts')
if (dirent.isDir) {
const methodsOfIndexTsFile =
tree.children.find(c => c.name === `${file}.ts`) ??
dirent.tree.children.find(c => c.name === 'index.ts')

return createApiString(
target,
dirent.tree,
`${importBasePath}/${file}`,
indent,
`${indent} `,
newUrl,
valFn.replace('<% next %>', '<% props %>'),
dirList.includes(`${file}.ts`)
? getMethodsString(`${importBasePath}/${file}`, `${target}.ts`, indent, newUrl)
: fs.existsSync(indexPath)
? getMethodsString(`${importBasePath}/${file}/index`, indexPath, indent, newUrl)
methodsOfIndexTsFile?.isDir === false
? getMethodsString(
`${importBasePath}/${file}`,
methodsOfIndexTsFile.methods,
indent,
newUrl
)
: undefined
)
} else if (
path.extname(file) === '.ts' &&
file !== 'index.ts' &&
!dirList.includes(basename)
) {
} else if (file !== 'index.ts' && tree.children.every(d => d.name !== basename)) {
return valFn.replace(
'<% next %>',
getMethodsString(`${importBasePath}/${basename}`, target, indent, newUrl)
getMethodsString(`${importBasePath}/${basename}`, dirent.methods, indent, newUrl)
)
}
})
Expand All @@ -96,17 +83,16 @@ export default (input: string, trailingSlash: boolean) => {
)
}

const rootIndexPath = path.posix.join(input, 'index.ts')
const rootIndent = ' '
const emptyMethodsRegExp = /.+{\n\n? +},?\n/
const rootIndexData = direntTree.children.find(c => c.name === 'index.ts')
let api = createApiString(
input,
direntTree,
'.',
rootIndent,
' ',
'',
`{\n<% props %>\n }`,
fs.existsSync(rootIndexPath)
? getMethodsString('./index', rootIndexPath, rootIndent, '')
rootIndexData && !rootIndexData.isDir
? getMethodsString('./index', rootIndexData.methods, ' ', '')
: undefined
)

Expand Down
48 changes: 48 additions & 0 deletions packages/aspida/src/getDirentTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import fs from 'fs'
import parseInterface, { Method } from './parseInterface'

type FileData = {
name: string
isDir: false
methods: Method[]
}

type DirData = {
name: string
isDir: true
tree: DirentTree
}

export type DirentTree = { path: string; children: (FileData | DirData)[] }

export const getDirentTree = (input: string) => {
const tree: DirentTree = { path: input, children: [] }

fs.readdirSync(input, { withFileTypes: true })
.filter(dirent => !dirent.name.startsWith('$') && !dirent.name.startsWith('@'))
.sort((a, b) => (a.name < b.name ? -1 : 1))
.forEach(dirent => {
if (dirent.isDirectory()) {
tree.children.push({
name: dirent.name,
isDir: true,
tree: getDirentTree(`${input}/${dirent.name}`)
})
} else if (dirent.name.endsWith('.ts')) {
const methodsInterface = parseInterface(
fs.readFileSync(`${input}/${dirent.name}`, 'utf8'),
'Methods'
)
if (!methodsInterface || methodsInterface.every(({ props }) => !Object.keys(props).length))
return

tree.children.push({
name: dirent.name,
isDir: false,
methods: methodsInterface
})
}
})

return tree
}

0 comments on commit 2842e61

Please sign in to comment.