diff --git a/jest/common.ts b/jest/common.ts index be87bb9..43328a6 100644 --- a/jest/common.ts +++ b/jest/common.ts @@ -37,3 +37,27 @@ export namespace Param_1 { name: string; } } + +export namespace ParamsRule { + export interface Level { + a?: boolean; + b?: boolean; + c?: boolean; + d?: boolean; + } + + export enum PEnum { + 'enum0' = 'enum0' + } + + export interface PObject { + a: Level; + b?: PEnum; + c?: PEnum[]; + } + + export interface PAll { + level?: Level; + pObject?: PObject; + } +} \ No newline at end of file diff --git a/jest/namespace.ts b/jest/namespace.ts index e86b97a..f640730 100644 --- a/jest/namespace.ts +++ b/jest/namespace.ts @@ -1,4 +1,4 @@ -import { Param, Param_1 } from './common'; +import { Param, Param_1, ParamsRule } from './common'; import * as Type from './common'; export interface Namespace_1 { @@ -18,3 +18,7 @@ export interface Namespace_4 { other2: Param_1.A; other3: Param_1.Label; } + +export interface Namespace_5 { + other1: ParamsRule.PAll +} \ No newline at end of file diff --git a/src/__tests__/__snapshots__/namespace.test.ts.snap b/src/__tests__/__snapshots__/namespace.test.ts.snap index f431e75..495c6ff 100644 --- a/src/__tests__/__snapshots__/namespace.test.ts.snap +++ b/src/__tests__/__snapshots__/namespace.test.ts.snap @@ -139,3 +139,77 @@ Object { "type": "object", } `; + +exports[`namespace案例_5 1`] = ` +Object { + "additionalProperties": false, + "definitions": Object { + "ParamsRule.Level": Object { + "additionalProperties": false, + "properties": Object { + "a": Object { + "type": "boolean", + }, + "b": Object { + "type": "boolean", + }, + "c": Object { + "type": "boolean", + }, + "d": Object { + "type": "boolean", + }, + }, + "type": "object", + }, + "ParamsRule.PAll": Object { + "additionalProperties": false, + "properties": Object { + "level": Object { + "$ref": "#/definitions/ParamsRule.Level", + }, + "pObject": Object { + "$ref": "#/definitions/ParamsRule.PObject", + }, + }, + "type": "object", + }, + "ParamsRule.PEnum": Object { + "enum": Array [ + "enum0", + ], + "type": "string", + }, + "ParamsRule.PObject": Object { + "additionalProperties": false, + "properties": Object { + "a": Object { + "$ref": "#/definitions/ParamsRule.Level", + }, + "b": Object { + "$ref": "#/definitions/ParamsRule.PEnum", + }, + "c": Object { + "items": Object { + "$ref": "#/definitions/ParamsRule.PEnum", + }, + "type": "array", + }, + }, + "required": Array [ + "a", + ], + "type": "object", + }, + }, + "properties": Object { + "other1": Object { + "$ref": "#/definitions/ParamsRule.PAll", + }, + }, + "required": Array [ + "other1", + ], + "type": "object", +} +`; diff --git a/src/__tests__/__snapshots__/other.test.ts.snap b/src/__tests__/__snapshots__/other.test.ts.snap index c617c34..0a3a4de 100644 --- a/src/__tests__/__snapshots__/other.test.ts.snap +++ b/src/__tests__/__snapshots__/other.test.ts.snap @@ -270,6 +270,63 @@ Object { ], "type": "number", }, + "ParamsRule.Level": Object { + "additionalProperties": false, + "properties": Object { + "a": Object { + "type": "boolean", + }, + "b": Object { + "type": "boolean", + }, + "c": Object { + "type": "boolean", + }, + "d": Object { + "type": "boolean", + }, + }, + "type": "object", + }, + "ParamsRule.PAll": Object { + "additionalProperties": false, + "properties": Object { + "level": Object { + "$ref": "#ParamsRule.Level", + }, + "pObject": Object { + "$ref": "#ParamsRule.PObject", + }, + }, + "type": "object", + }, + "ParamsRule.PEnum": Object { + "enum": Array [ + "enum0", + ], + "type": "string", + }, + "ParamsRule.PObject": Object { + "additionalProperties": false, + "properties": Object { + "a": Object { + "$ref": "#ParamsRule.Level", + }, + "b": Object { + "$ref": "#ParamsRule.PEnum", + }, + "c": Object { + "items": Object { + "$ref": "#ParamsRule.PEnum", + }, + "type": "array", + }, + }, + "required": Array [ + "a", + ], + "type": "object", + }, }, "/jest/other.ts": Object { "AAA": Object { diff --git a/src/__tests__/namespace.test.ts b/src/__tests__/namespace.test.ts index 666f72a..12aac8d 100644 --- a/src/__tests__/namespace.test.ts +++ b/src/__tests__/namespace.test.ts @@ -25,3 +25,7 @@ test('namespace案例_3', () => { test('namespace案例_4', () => { expect(getSchema('Namespace_4')).toMatchSnapshot(); }); + +test('namespace案例_5', () => { + expect(getSchema('Namespace_5')).toMatchSnapshot(); +}); diff --git a/src/get-jsonschema-from-data.ts b/src/get-jsonschema-from-data.ts index 453ce24..d5b1cc4 100644 --- a/src/get-jsonschema-from-data.ts +++ b/src/get-jsonschema-from-data.ts @@ -312,18 +312,25 @@ export default class genTypeSchema extends typescriptToFileDatas { // 兼容import外部引入与内部引用两种方式 let $refJson = fileJson[firstKey] || fileJson[$refKey] || {}; $refJson = _.cloneDeep($refJson) + if ((entry as any).keySet.has($refKey)) { (entry as any).refKeyTime[$refKey] = ((entry as any).refKeyTime[$refKey] || 0) + 1; + // 处理namespace方式导入的types + if ($refJson.type === ImportType.ImportNamespaceSpecifier) { + $refKey = otherKeys.join('.'); + } + item.$ref = `#/definitions/${$refKey}`; return $refJson; } - (entry as any).keySet.add($refKey); - (entry as any).refKeyTime[$refKey] = ((entry as any).refKeyTime[$refKey] || 0) + 1; // 处理namespace方式导入的types if ($refJson.type === ImportType.ImportNamespaceSpecifier) { $refKey = otherKeys.join('.'); } + (entry as any).keySet.add($refKey); + (entry as any).refKeyTime[$refKey] = ((entry as any).refKeyTime[$refKey] || 0) + 1; + item.$ref = `#/definitions/${$refKey}`; // fileJson[$refJson.$ref.replace(/#(\/definitions\/)?/, '')] 表示在本文件就能找到 diff --git a/src/types.ts b/src/types.ts index 3fd7bbc..5af2f7d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -43,12 +43,14 @@ export interface TypeAnnotationConfig { file?: string; attrKey?: string; refKey?: string; + namespaces?: string[]; } export interface TSTypeAnnotationConfig { node: AnyOption; parentKey?: string; file?: string; + namespaces?: string[]; } export type EntryType = { keySet: Set; times: number }; diff --git a/src/typescript-to-file-datas.ts b/src/typescript-to-file-datas.ts index 9ac6244..fbdb59b 100644 --- a/src/typescript-to-file-datas.ts +++ b/src/typescript-to-file-datas.ts @@ -81,7 +81,7 @@ export default class typescriptToFileDatas { parentJson: null | AnyOption, option: TSTypeAnnotationConfig, ): void { - const { node, parentKey, file } = option || {}; + const { node, parentKey, file, namespaces } = option || {}; const key = _.get(node, 'key.name') || _.get(node, 'key.value') || ''; const required = !node.optional; @@ -92,6 +92,7 @@ export default class typescriptToFileDatas { typeAnnotation: node.typeAnnotation, file, attrKey: key, + namespaces, }); if (typeAnnotation && typeof typeAnnotation === 'object') { @@ -338,7 +339,7 @@ export default class typescriptToFileDatas { } const key = _.get(path, 'node.key.name') || _.get(path, 'node.key.value'); - _this.handleTSTypeAnnotation(json, null, { node: path.node, file }); + _this.handleTSTypeAnnotation(json, null, { node: path.node, file, namespaces, }); path.traverse({ TSTypeLiteral(path: AnyOption) { @@ -352,6 +353,7 @@ export default class typescriptToFileDatas { node: path.node, parentKey: key, file, + namespaces, }); }, }); @@ -576,10 +578,12 @@ export default class typescriptToFileDatas { * @param {AnyOption} typeAnnotation * @returns {any} {string} */ - getTypeName(typeName: AnyOption): string { + getTypeName(typeName: AnyOption, namespaces?: string[]): string { const name = _.get(typeName, 'name'); - if (name) { + if (typeName.type === 'Identifier' && Array.isArray(namespaces) && namespaces.length) { + return `${namespaces.join('.')}.${name}` + } return name; } const { left, right } = typeName || {}; @@ -624,7 +628,7 @@ export default class typescriptToFileDatas { * @returns {any} */ transformTypeAnnotation(option: TypeAnnotationConfig): AnyOption | null { - const { typeAnnotation, file, attrKey, refKey } = option || {}; + const { typeAnnotation, file, attrKey, refKey, namespaces } = option || {}; if (!typeAnnotation) return null; const cType = _.get(typeAnnotation, 'type'); if (!cType) return null; @@ -648,10 +652,8 @@ export default class typescriptToFileDatas { // 处理 Number/自定义 等类型 if (cType === 'TSTypeReference') { - const name = this.getTypeName(typeAnnotation.typeName); - + const name = this.getTypeName(typeAnnotation.typeName, namespaces); const type = this.handleRelationTypes(name); - let items = null; if (typeAnnotation.typeParameters) { items = this.transformTypeAnnotation({ @@ -659,6 +661,7 @@ export default class typescriptToFileDatas { file, attrKey, refKey: name, + namespaces, }); } // promise 特殊处理 @@ -698,7 +701,12 @@ export default class typescriptToFileDatas { if (cType === 'TSTypeParameterInstantiation') { const params: (AnyOption | null)[] = []; typeAnnotation.params.forEach((item: AnyOption) => { - const res = this.transformTypeAnnotation({ typeAnnotation: item, file, attrKey }); + const res = this.transformTypeAnnotation({ + typeAnnotation: item, + file, + attrKey, + namespaces, + }); if (res) { params.push(res); } @@ -718,6 +726,7 @@ export default class typescriptToFileDatas { typeAnnotation: typeAnnotation.typeAnnotation, file, attrKey, + namespaces, }); } @@ -727,6 +736,7 @@ export default class typescriptToFileDatas { typeAnnotation: typeAnnotation.elementType, file, attrKey, + namespaces, }); return type ? { type: 'array', items: type } : null; } @@ -737,6 +747,7 @@ export default class typescriptToFileDatas { typeAnnotation: typeAnnotation.typeAnnotation, file, attrKey, + namespaces, }); return type; } @@ -745,7 +756,7 @@ export default class typescriptToFileDatas { const members = typeAnnotation.members || []; const json = { type: 'object', properties: {}, required: [] }; members.forEach((item: AnyOption) => { - this.handleTSTypeAnnotation(json, null, { node: item, file }); + this.handleTSTypeAnnotation(json, null, { node: item, file, namespaces, }); }); this.formatJsonSchema(json);