fix: avoid false namespace export conflicts
This commit is contained in:
parent
89f43483ae
commit
57a2492408
14
README.md
14
README.md
|
|
@ -352,8 +352,8 @@ import { getCurriculumListApi } from '@/api/aixue/generated'
|
||||||
|
|
||||||
- 如果不同模块里恰好生成了同名函数,例如都生成了 `getListApi`
|
- 如果不同模块里恰好生成了同名函数,例如都生成了 `getListApi`
|
||||||
- 那么 `generated/index.js` 里的 `export * from './module'` 会产生冲突
|
- 那么 `generated/index.js` 里的 `export * from './module'` 会产生冲突
|
||||||
- 如果某个扁平函数名刚好和模块命名空间导出名撞上,例如模块命名空间是 `rankingApi`,同时模块里也生成了 `rankingApi`
|
- 如果某个接口的默认函数名刚好会和模块命名空间导出名撞上,例如 `/api/Values` 同时会推导出模块命名空间 `valuesApi`
|
||||||
- 这类情况也会被当成冲突处理
|
- 工具会在生成阶段自动把函数名调整成不冲突的形式,例如 `getValuesApi`
|
||||||
- 工具会先列出冲突函数、对应模块名,以及能识别到的完整接口 URL
|
- 工具会先列出冲突函数、对应模块名,以及能识别到的完整接口 URL
|
||||||
- 在交互终端里会给你两个选择:
|
- 在交互终端里会给你两个选择:
|
||||||
- `1` 在函数名后自动追加模块名,例如 `getListEnglishWordApi`
|
- `1` 在函数名后自动追加模块名,例如 `getListEnglishWordApi`
|
||||||
|
|
@ -502,12 +502,12 @@ npx yx-generate-api generate Curriculum
|
||||||
|
|
||||||
### 6. 为什么生成时报“Duplicate API export names detected”
|
### 6. 为什么生成时报“Duplicate API export names detected”
|
||||||
|
|
||||||
说明 `generated/index.js` 里出现了重复导出名。
|
说明不同模块之间出现了重复的扁平函数导出名。
|
||||||
|
|
||||||
常见场景有两种:
|
常见场景有两种:
|
||||||
|
|
||||||
- 两个或多个模块里生成了同名函数,例如都导出了 `getListApi`
|
- 两个或多个模块里生成了同名函数,例如都导出了 `getListApi`
|
||||||
- 某个扁平函数名和模块命名空间导出名撞上,例如模块命名空间是 `rankingApi`,同时模块里也生成了 `rankingApi`
|
- 你只生成了部分模块,但保留目录里已有模块,导致新旧模块之间出现了同名导出
|
||||||
|
|
||||||
因为 `generated/index.js` 会使用:
|
因为 `generated/index.js` 会使用:
|
||||||
|
|
||||||
|
|
@ -516,7 +516,11 @@ export * from './module-a'
|
||||||
export * from './module-b'
|
export * from './module-b'
|
||||||
```
|
```
|
||||||
|
|
||||||
这种模式下,重复导出名不能直接共存,命名空间导出也不能把同名扁平导出安全暴露出来。
|
这种模式下,重复的扁平导出名不能直接共存。
|
||||||
|
|
||||||
|
像 `/api/Values` 这类“函数默认名刚好和模块命名空间名相同”的情况,工具会在生成阶段自动规避,不会再单独报这个冲突。
|
||||||
|
|
||||||
|
如果你是从旧版本升级过来,而 `generated` 目录里还保留着旧规则生成的模块文件,也可能在部分生成时触发这类校验。遇到这种情况,直接做一次全量生成,或者把冲突模块一起重新生成即可。
|
||||||
|
|
||||||
所以工具会先把冲突明细列出来,内容会尽量包含:
|
所以工具会先把冲突明细列出来,内容会尽量包含:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,12 +130,7 @@ const createDuplicateExportResolver = () => {
|
||||||
console.log(`- 冲突函数:${conflict.exportName}`)
|
console.log(`- 冲突函数:${conflict.exportName}`)
|
||||||
|
|
||||||
for (const occurrence of conflict.occurrences) {
|
for (const occurrence of conflict.occurrences) {
|
||||||
const locationText =
|
const locationText = occurrence.path ? `URL: ${occurrence.path}` : 'URL: 当前保留的已生成模块'
|
||||||
occurrence.sourceType === 'namespace'
|
|
||||||
? '类型: 模块命名空间导出'
|
|
||||||
: occurrence.path
|
|
||||||
? `URL: ${occurrence.path}`
|
|
||||||
: 'URL: 当前保留的已生成模块'
|
|
||||||
console.log(
|
console.log(
|
||||||
` 模块: ${occurrence.moduleName} | 文件: ${occurrence.fileName} | ${locationText}`,
|
` 模块: ${occurrence.moduleName} | 文件: ${occurrence.fileName} | ${locationText}`,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,27 @@ export const generateApiFiles = async ({
|
||||||
skipFileNames: selectedModuleFileNames,
|
skipFileNames: selectedModuleFileNames,
|
||||||
skipRemovableAutoGeneratedFiles: shouldRemoveStaleGeneratedFiles,
|
skipRemovableAutoGeneratedFiles: shouldRemoveStaleGeneratedFiles,
|
||||||
})
|
})
|
||||||
|
const reservedNamespaceFunctionNames = new Set(
|
||||||
|
[...selectedModules.map((moduleInfo) => moduleInfo.fileName), ...retainedModuleExports.map((item) => item.fileName)].map(
|
||||||
|
(fileName) => toCamelCase(fileName),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const moduleInfo of selectedModules) {
|
||||||
|
assignFunctionNames(moduleInfo.operations, reservedNamespaceFunctionNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
const namespaceConflicts = findNamespaceExportConflicts([
|
||||||
|
...buildPlannedModuleExports(selectedModules),
|
||||||
|
...retainedModuleExports,
|
||||||
|
])
|
||||||
|
|
||||||
|
if (namespaceConflicts.length) {
|
||||||
|
throw createDuplicateModuleExportsError(namespaceConflicts, {
|
||||||
|
reason: 'namespace-conflict',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const duplicateConflicts = findDuplicateModuleExports([
|
const duplicateConflicts = findDuplicateModuleExports([
|
||||||
...buildPlannedModuleExports(selectedModules),
|
...buildPlannedModuleExports(selectedModules),
|
||||||
...retainedModuleExports,
|
...retainedModuleExports,
|
||||||
|
|
@ -89,14 +110,19 @@ export const generateApiFiles = async ({
|
||||||
|
|
||||||
if (resolution?.action === 'rename') {
|
if (resolution?.action === 'rename') {
|
||||||
const renameEntries = applyDuplicateExportRenameStrategy(selectedModules, duplicateConflicts)
|
const renameEntries = applyDuplicateExportRenameStrategy(selectedModules, duplicateConflicts)
|
||||||
|
const remainingNamespaceConflicts = findNamespaceExportConflicts([
|
||||||
|
...buildPlannedModuleExports(selectedModules),
|
||||||
|
...retainedModuleExports,
|
||||||
|
])
|
||||||
const remainingConflicts = findDuplicateModuleExports([
|
const remainingConflicts = findDuplicateModuleExports([
|
||||||
...buildPlannedModuleExports(selectedModules),
|
...buildPlannedModuleExports(selectedModules),
|
||||||
...retainedModuleExports,
|
...retainedModuleExports,
|
||||||
])
|
])
|
||||||
|
|
||||||
if (remainingConflicts.length) {
|
if (remainingNamespaceConflicts.length || remainingConflicts.length) {
|
||||||
throw createDuplicateModuleExportsError(remainingConflicts, {
|
throw createDuplicateModuleExportsError(remainingConflicts, {
|
||||||
reason: 'rename-failed',
|
reason: 'rename-failed',
|
||||||
|
supplementalConflicts: remainingNamespaceConflicts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,22 +306,15 @@ const readRetainedModuleExports = async ({
|
||||||
fileName,
|
fileName,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
moduleName,
|
moduleName,
|
||||||
occurrences: [
|
occurrences: extractGeneratedModuleExportNames(content).map((exportName) =>
|
||||||
buildNamespaceExportOccurrence({
|
buildFlatExportOccurrence({
|
||||||
|
exportName,
|
||||||
fileName,
|
fileName,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
moduleName,
|
moduleName,
|
||||||
|
path: null,
|
||||||
}),
|
}),
|
||||||
...extractGeneratedModuleExportNames(content).map((exportName) =>
|
),
|
||||||
buildFlatExportOccurrence({
|
|
||||||
exportName,
|
|
||||||
fileName,
|
|
||||||
isSelected: false,
|
|
||||||
moduleName,
|
|
||||||
path: null,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
).then((items) => items.filter(Boolean))
|
).then((items) => items.filter(Boolean))
|
||||||
|
|
@ -314,22 +333,15 @@ const buildPlannedModuleExports = (selectedModules) => {
|
||||||
fileName: moduleInfo.fileName,
|
fileName: moduleInfo.fileName,
|
||||||
isSelected: true,
|
isSelected: true,
|
||||||
moduleName: moduleInfo.moduleName,
|
moduleName: moduleInfo.moduleName,
|
||||||
occurrences: [
|
occurrences: moduleInfo.operations.map((operationItem) =>
|
||||||
buildNamespaceExportOccurrence({
|
buildFlatExportOccurrence({
|
||||||
|
exportName: `${operationItem.functionName}Api`,
|
||||||
fileName: moduleInfo.fileName,
|
fileName: moduleInfo.fileName,
|
||||||
isSelected: false,
|
isSelected: true,
|
||||||
moduleName: moduleInfo.moduleName,
|
moduleName: moduleInfo.moduleName,
|
||||||
|
path: operationItem.path,
|
||||||
}),
|
}),
|
||||||
...moduleInfo.operations.map((operationItem) =>
|
),
|
||||||
buildFlatExportOccurrence({
|
|
||||||
exportName: `${operationItem.functionName}Api`,
|
|
||||||
fileName: moduleInfo.fileName,
|
|
||||||
isSelected: true,
|
|
||||||
moduleName: moduleInfo.moduleName,
|
|
||||||
path: operationItem.path,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +386,6 @@ const buildModuleMap = (swagger) => {
|
||||||
|
|
||||||
for (const moduleInfo of moduleMap.values()) {
|
for (const moduleInfo of moduleMap.values()) {
|
||||||
moduleInfo.operations.sort(compareOperations)
|
moduleInfo.operations.sort(compareOperations)
|
||||||
assignFunctionNames(moduleInfo.operations)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return moduleMap
|
return moduleMap
|
||||||
|
|
@ -576,11 +587,11 @@ const readGeneratedModuleName = (content) => {
|
||||||
return match?.[1]?.trim() || ''
|
return match?.[1]?.trim() || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildNamespaceExportOccurrence = ({ fileName, isSelected, moduleName }) => {
|
const buildNamespaceExportOccurrence = ({ fileName, moduleName }) => {
|
||||||
return {
|
return {
|
||||||
exportName: buildModuleNamespaceExportName(fileName),
|
exportName: buildModuleNamespaceExportName(fileName),
|
||||||
fileName,
|
fileName,
|
||||||
isSelected,
|
isSelected: false,
|
||||||
moduleName,
|
moduleName,
|
||||||
path: null,
|
path: null,
|
||||||
sourceType: 'namespace',
|
sourceType: 'namespace',
|
||||||
|
|
@ -620,12 +631,52 @@ const findDuplicateModuleExports = (moduleExports) => {
|
||||||
.sort((left, right) => left.exportName.localeCompare(right.exportName))
|
.sort((left, right) => left.exportName.localeCompare(right.exportName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findNamespaceExportConflicts = (moduleExports) => {
|
||||||
|
const namespaceOccurrences = moduleExports.map((moduleExport) =>
|
||||||
|
buildNamespaceExportOccurrence({
|
||||||
|
fileName: moduleExport.fileName,
|
||||||
|
moduleName: moduleExport.moduleName,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
const namespaceMap = new Map(
|
||||||
|
namespaceOccurrences.map((occurrence) => [occurrence.exportName, occurrence]),
|
||||||
|
)
|
||||||
|
const conflicts = new Map()
|
||||||
|
|
||||||
|
for (const moduleExport of moduleExports) {
|
||||||
|
for (const occurrence of moduleExport.occurrences) {
|
||||||
|
const namespaceOccurrence = namespaceMap.get(occurrence.exportName)
|
||||||
|
|
||||||
|
if (!namespaceOccurrence) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conflicts.has(occurrence.exportName)) {
|
||||||
|
conflicts.set(occurrence.exportName, {
|
||||||
|
exportName: occurrence.exportName,
|
||||||
|
occurrences: [namespaceOccurrence],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
conflicts.get(occurrence.exportName).occurrences.push(occurrence)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...conflicts.values()]
|
||||||
|
.map((conflict) => ({
|
||||||
|
...conflict,
|
||||||
|
occurrences: conflict.occurrences.sort(compareDuplicateOccurrences),
|
||||||
|
}))
|
||||||
|
.filter((conflict) => conflict.occurrences.length > 1)
|
||||||
|
.sort((left, right) => left.exportName.localeCompare(right.exportName))
|
||||||
|
}
|
||||||
|
|
||||||
const applyDuplicateExportRenameStrategy = (selectedModules, conflicts) => {
|
const applyDuplicateExportRenameStrategy = (selectedModules, conflicts) => {
|
||||||
const renameEntries = []
|
const renameEntries = []
|
||||||
|
|
||||||
for (const conflict of conflicts) {
|
for (const conflict of conflicts) {
|
||||||
for (const occurrence of conflict.occurrences) {
|
for (const occurrence of conflict.occurrences) {
|
||||||
if (!occurrence.isSelected || occurrence.sourceType !== 'flat') {
|
if (!occurrence.isSelected) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -683,45 +734,45 @@ const compareDuplicateOccurrences = (left, right) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertNoDuplicateModuleExports = (moduleExports) => {
|
const assertNoDuplicateModuleExports = (moduleExports) => {
|
||||||
const duplicateConflicts = findDuplicateModuleExports(
|
const normalizedModuleExports = moduleExports.map((moduleExport) => ({
|
||||||
moduleExports.map((moduleExport) => ({
|
fileName: moduleExport.fileName,
|
||||||
fileName: moduleExport.fileName,
|
isSelected: false,
|
||||||
isSelected: false,
|
moduleName: moduleExport.fileName,
|
||||||
moduleName: moduleExport.fileName,
|
occurrences: moduleExport.exportNames.map((exportName) =>
|
||||||
occurrences: [
|
buildFlatExportOccurrence({
|
||||||
buildNamespaceExportOccurrence({
|
exportName,
|
||||||
fileName: moduleExport.fileName,
|
fileName: moduleExport.fileName,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
moduleName: moduleExport.fileName,
|
moduleName: moduleExport.fileName,
|
||||||
}),
|
path: null,
|
||||||
...moduleExport.exportNames.map((exportName) =>
|
}),
|
||||||
buildFlatExportOccurrence({
|
),
|
||||||
exportName,
|
}))
|
||||||
fileName: moduleExport.fileName,
|
const namespaceConflicts = findNamespaceExportConflicts(normalizedModuleExports)
|
||||||
isSelected: false,
|
const duplicateConflicts = findDuplicateModuleExports(normalizedModuleExports)
|
||||||
moduleName: moduleExport.fileName,
|
|
||||||
path: null,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!duplicateConflicts.length) {
|
if (!namespaceConflicts.length && !duplicateConflicts.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
throw createDuplicateModuleExportsError(duplicateConflicts, {
|
throw createDuplicateModuleExportsError(duplicateConflicts, {
|
||||||
reason: 'unresolved',
|
reason: namespaceConflicts.length ? 'namespace-conflict' : 'unresolved',
|
||||||
|
supplementalConflicts: namespaceConflicts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const createDuplicateModuleExportsError = (conflicts, { reason = 'unresolved' } = {}) => {
|
const createDuplicateModuleExportsError = (
|
||||||
|
conflicts,
|
||||||
|
{ reason = 'unresolved', supplementalConflicts = [] } = {},
|
||||||
|
) => {
|
||||||
|
const allConflicts = [...supplementalConflicts, ...conflicts]
|
||||||
const reasonMessage =
|
const reasonMessage =
|
||||||
reason === 'user-aborted'
|
reason === 'user-aborted'
|
||||||
? 'Generation cancelled because duplicate exports were not resolved.'
|
? 'Generation cancelled because duplicate exports were not resolved.'
|
||||||
: reason === 'rename-failed'
|
: reason === 'rename-failed'
|
||||||
? 'Automatic rename still leaves duplicate exports, so generation has been aborted.'
|
? 'Automatic rename still leaves duplicate exports, so generation has been aborted.'
|
||||||
|
: reason === 'namespace-conflict'
|
||||||
|
? 'A flat API export still conflicts with a module namespace export. Regenerate the affected modules or run a full generate to repair stale generated files.'
|
||||||
: 'Current index export mode uses "export * from \'./module\'", so duplicate names are not allowed. Run this command in an interactive terminal to choose rename or exit.'
|
: 'Current index export mode uses "export * from \'./module\'", so duplicate names are not allowed. Run this command in an interactive terminal to choose rename or exit.'
|
||||||
|
|
||||||
return new Error(
|
return new Error(
|
||||||
|
|
@ -729,7 +780,7 @@ const createDuplicateModuleExportsError = (conflicts, { reason = 'unresolved' }
|
||||||
'Duplicate API export names detected across generated modules.',
|
'Duplicate API export names detected across generated modules.',
|
||||||
reasonMessage,
|
reasonMessage,
|
||||||
'',
|
'',
|
||||||
...formatDuplicateConflictLines(conflicts),
|
...formatDuplicateConflictLines(allConflicts),
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1214,8 +1265,8 @@ const compareOperations = (left, right) => {
|
||||||
return HTTP_METHOD_ORDER.indexOf(left.method) - HTTP_METHOD_ORDER.indexOf(right.method)
|
return HTTP_METHOD_ORDER.indexOf(left.method) - HTTP_METHOD_ORDER.indexOf(right.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
const assignFunctionNames = (operations) => {
|
const assignFunctionNames = (operations, reservedNames = new Set()) => {
|
||||||
const usedNames = new Set()
|
const usedNames = new Set(reservedNames)
|
||||||
|
|
||||||
for (const item of operations) {
|
for (const item of operations) {
|
||||||
const baseName = ensureIdentifier(toCamelCase(getEndpointName(item.path)))
|
const baseName = ensureIdentifier(toCamelCase(getEndpointName(item.path)))
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ test('generation can rename duplicate exports by appending module names', async
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
test('generation renames flat exports that conflict with module namespace exports', async () => {
|
test('generation automatically avoids collisions with module namespace export names', async () => {
|
||||||
const tempDir = await createTempDir()
|
const tempDir = await createTempDir()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -286,9 +286,9 @@ test('generation renames flat exports that conflict with module namespace export
|
||||||
await writeJson(swaggerPath, {
|
await writeJson(swaggerPath, {
|
||||||
openapi: '3.0.0',
|
openapi: '3.0.0',
|
||||||
paths: {
|
paths: {
|
||||||
'/api/v1/Ranking': {
|
'/api/Values': {
|
||||||
get: {
|
get: {
|
||||||
tags: ['Ranking'],
|
tags: ['Values'],
|
||||||
responses: {
|
responses: {
|
||||||
200: { description: 'OK' },
|
200: { description: 'OK' },
|
||||||
},
|
},
|
||||||
|
|
@ -306,19 +306,65 @@ test('generation renames flat exports that conflict with module namespace export
|
||||||
paramStyle: 'object',
|
paramStyle: 'object',
|
||||||
modules: [],
|
modules: [],
|
||||||
cleanOutput: true,
|
cleanOutput: true,
|
||||||
resolveDuplicateExports: async ({ conflicts }) => {
|
})
|
||||||
assert.equal(conflicts.length, 1)
|
|
||||||
assert.equal(conflicts[0].exportName, 'rankingApi')
|
const valuesContent = await readFile(path.join(outputDir, 'values.js'))
|
||||||
return { action: 'rename' }
|
const indexContent = await readFile(path.join(outputDir, 'index.js'))
|
||||||
|
|
||||||
|
assert.match(valuesContent, /const getValuesApi =/)
|
||||||
|
assert.match(indexContent, /export \* as valuesApi from ["']\.\/values["']/)
|
||||||
|
assert.match(indexContent, /export \* from ["']\.\/values["']/)
|
||||||
|
} finally {
|
||||||
|
await fs.rm(tempDir, { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('partial generation fails when retained generated files still collide with namespace exports', async () => {
|
||||||
|
const tempDir = await createTempDir()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const swaggerPath = path.join(tempDir, 'swagger.json')
|
||||||
|
const outputDir = path.join(tempDir, 'generated')
|
||||||
|
|
||||||
|
await fs.mkdir(outputDir, { recursive: true })
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(outputDir, 'values.js'),
|
||||||
|
`// Auto-generated. Do not edit manually.
|
||||||
|
// Module: Values
|
||||||
|
const valuesApi = () => null
|
||||||
|
|
||||||
|
export { valuesApi }
|
||||||
|
`,
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
|
|
||||||
|
await writeJson(swaggerPath, {
|
||||||
|
openapi: '3.0.0',
|
||||||
|
paths: {
|
||||||
|
'/api/v1/Alpha/GetThing': {
|
||||||
|
get: {
|
||||||
|
tags: ['Alpha'],
|
||||||
|
responses: {
|
||||||
|
200: { description: 'OK' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const rankingContent = await readFile(path.join(outputDir, 'ranking.js'))
|
await assert.rejects(
|
||||||
const indexContent = await readFile(path.join(outputDir, 'index.js'))
|
generateApiFiles({
|
||||||
|
projectRoot: tempDir,
|
||||||
assert.match(rankingContent, /const rankingRankingApi =/)
|
swaggerUrl: swaggerPath,
|
||||||
assert.match(indexContent, /export \* as rankingApi from ["']\.\/ranking["']/)
|
swaggerTimeoutMs: 1000,
|
||||||
assert.match(indexContent, /export \* from ["']\.\/ranking["']/)
|
outputDir,
|
||||||
|
requestImport: '../request',
|
||||||
|
paramStyle: 'object',
|
||||||
|
modules: ['Alpha'],
|
||||||
|
cleanOutput: true,
|
||||||
|
}),
|
||||||
|
/namespace export/,
|
||||||
|
)
|
||||||
} finally {
|
} finally {
|
||||||
await fs.rm(tempDir, { recursive: true, force: true })
|
await fs.rm(tempDir, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue