Skip to content

Commit

Permalink
feat: support escapeChars config
Browse files Browse the repository at this point in the history
  • Loading branch information
headwindz authored and PengJiyuan committed Mar 14, 2023
1 parent b178052 commit 1a45f01
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 20 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,13 @@ When parsing nested types, whether to ignore these nested types if they are defi
When returning true, nested types must not be exported, but when false is returned,
nested types may not be exported due to other reasons (such as the nested type has jsdoc @title, which needs to be manually exported)

## Who's using?
### escapeChars

`boolean`: default to `true`

Whether to escape characters for extracted type text. E.g. `|` will be escaped to `\|`, `<Promise>` will be escaped to `&lt;Promise&gt;`.

## Who's using?

[Arco Design](https://github.com/arco-design/arco-design) - A comprehensive React UI components library based on Arco Design.

Expand Down
101 changes: 90 additions & 11 deletions __test__/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,59 @@ Object {
}
`;

exports[`generate escape 1`] = `
Object {
"A": Object {
"data": Array [
Object {
"isOptional": true,
"name": "size",
"tags": Array [
Object {
"name": "zh",
"value": "尺寸",
},
Object {
"name": "en",
"value": "size",
},
],
"type": "'mini' | 'large' | 'default'",
},
Object {
"isOptional": true,
"name": "fetchData",
"tags": Array [
Object {
"name": "zh",
"value": "获取数据函数",
},
Object {
"name": "en",
"value": "Function to fetch data",
},
],
"type": "() => Promise<string>",
},
],
"tags": Array [
Object {
"name": "title",
"value": "A",
},
Object {
"name": "zh",
"value": "这是接口描述。",
},
Object {
"name": "en",
"value": "This is interface description.",
},
],
},
}
`;

exports[`generate extends 1`] = `
Object {
"Alert": Object {
Expand Down Expand Up @@ -434,7 +487,7 @@ Object {
},
"ButtonType": Object {
"data": "type ButtonType = {
size?: \\"mini\\" | \\"large\\" | \\"default\\";
size?: 'mini' | 'large' | 'default';
color?: string;
};
",
Expand Down Expand Up @@ -736,7 +789,7 @@ Object {
LEFT,
RIGHT,
UP,
DOWN,
DOWN
}
",
"isNestedType": true,
Expand Down Expand Up @@ -764,7 +817,7 @@ Object {
"data": "export interface OptionInfo extends PropsWithChildren<BlinkProps> {
valid: boolean;
index: number;
origin: \\"children\\" | \\"options\\" | \\"userCreatedOptions\\" | \\"userCreatingOption\\";
origin: 'children' | 'options' | 'userCreatedOptions' | 'userCreatingOption';
}
",
"isNestedType": true,
Expand Down Expand Up @@ -1087,7 +1140,7 @@ Object {
\`\`\`js
type ButtonType = {
size?: \\"mini\\" | \\"large\\" | \\"default\\";
size?: 'mini' | 'large' | 'default';
color?: string;
};
\`\`\`",
Expand Down Expand Up @@ -1157,13 +1210,39 @@ Add two numbers
\`\`\`js
type ButtonType = {
size?: \\"mini\\" | \\"large\\" | \\"default\\";
size?: 'mini' | 'large' | 'default';
color?: string;
};
\`\`\`",
]
`;
exports[`generateMarkdown escape 1`] = `
Object {
"A": "### A
这是接口描述。
|参数名|描述|类型|默认值|
|---|---|---|---|
|size|尺寸|'mini' | 'large' | 'default' |\`-\`|
|fetchData|获取数据函数|() => Promise<string> |\`-\`|",
}
`;
exports[`generateMarkdown escape 2`] = `
Object {
"A": "### A
This is interface description.
|Property|Description|Type|DefaultValue|
|---|---|---|---|
|size|size|'mini' | 'large' | 'default' |\`-\`|
|fetchData|Function to fetch data|() => Promise<string> |\`-\`|",
}
`;
exports[`generateMarkdown extends 1`] = `
Object {
"Alert": "### Alert
Expand Down Expand Up @@ -1255,7 +1334,7 @@ Object {
\`\`\`js
type ButtonType = {
size?: \\"mini\\" | \\"large\\" | \\"default\\";
size?: 'mini' | 'large' | 'default';
color?: string;
};
\`\`\`",
Expand Down Expand Up @@ -1325,7 +1404,7 @@ Add two numbers
\`\`\`js
type ButtonType = {
size?: \\"mini\\" | \\"large\\" | \\"default\\";
size?: 'mini' | 'large' | 'default';
color?: string;
};
\`\`\`",
Expand Down Expand Up @@ -1368,7 +1447,7 @@ enum Direction {
LEFT,
RIGHT,
UP,
DOWN,
DOWN
}
\`\`\`",
"InnerMethodsReturnType": "### InnerMethodsReturnType
Expand All @@ -1384,7 +1463,7 @@ interface InnerMethodsReturnType {
export interface OptionInfo extends PropsWithChildren<BlinkProps> {
valid: boolean;
index: number;
origin: \\"children\\" | \\"options\\" | \\"userCreatedOptions\\" | \\"userCreatingOption\\";
origin: 'children' | 'options' | 'userCreatedOptions' | 'userCreatingOption';
}
\`\`\`",
"Owner": "### Owner
Expand Down Expand Up @@ -1487,7 +1566,7 @@ enum Direction {
LEFT,
RIGHT,
UP,
DOWN,
DOWN
}
\`\`\`",
"InnerMethodsReturnType": "### InnerMethodsReturnType
Expand All @@ -1503,7 +1582,7 @@ interface InnerMethodsReturnType {
export interface OptionInfo extends PropsWithChildren<BlinkProps> {
valid: boolean;
index: number;
origin: \\"children\\" | \\"options\\" | \\"userCreatedOptions\\" | \\"userCreatingOption\\";
origin: 'children' | 'options' | 'userCreatedOptions' | 'userCreatingOption';
}
\`\`\`",
"Owner": "### Owner
Expand Down
23 changes: 23 additions & 0 deletions __test__/fixtures/escape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ReactNode } from 'react';

/**
* @title A
*
* @zh 这是接口描述。
*
* @en This is interface description.
*/
export interface AProps {
/**
* @zh 尺寸
* @en size
*/
size?: 'mini' | 'large' | 'default';
/**
* @zh 获取数据函数
* @en Function to fetch data
*/
fetchData?: () => Promise<string>;
}


25 changes: 25 additions & 0 deletions __test__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const pathDefaultMap = path.resolve(pathFixtures, 'defaultTypeMap.ts');
const pathFunction = path.resolve(pathFixtures, 'function.ts');
const pathPropertySorter = path.resolve(pathFixtures, 'propertySorter.ts');
const pathNest = path.resolve(pathFixtures, 'nest/interface.ts');
const pathEscape = path.resolve(pathFixtures, 'escape.ts');

const nestLinkFormatter = (options) => {
const { typeName, jsDocTitle, fullPath } = options;
Expand Down Expand Up @@ -82,6 +83,14 @@ describe('generate', () => {
});
expect(schema).toMatchSnapshot();
});

it('escape', () => {
const schema = generate(pathEscape, {
sourceFilesPaths: './**/*.ts',
escapeChars: false
});
expect(schema).toMatchSnapshot();
});
});

describe('generateMarkdown', () => {
Expand Down Expand Up @@ -160,4 +169,20 @@ describe('generateMarkdown', () => {
expect(markdownZh).toMatchSnapshot();
expect(markdownEn).toMatchSnapshot();
});

it('escape', () => {
const markdownZh = generateMarkdown(pathEscape, {
sourceFilesPaths: './**/*.ts',
lang: 'zh',
escapeChars: false

});
const markdownEn = generateMarkdown(pathEscape, {
sourceFilesPaths: './**/*.ts',
lang: 'en',
escapeChars: false
});
expect(markdownZh).toMatchSnapshot();
expect(markdownEn).toMatchSnapshot();
});
});
9 changes: 5 additions & 4 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import {
LinkFormatter,
} from './interface';
import { defaultTypeMap, defaultLinkFormatter } from './default';
import { toSingleLine, escape } from './util';
import { format } from 'prettier';
import { toSingleLine } from './util';

const dummyProject = new Project({ useInMemoryFileSystem: true });

Expand Down Expand Up @@ -174,7 +173,8 @@ function getDeclarationBySymbol(symbol?: Symbol) {

function getDeclarationTextBySymbol(symbol?: Symbol) {
const declaration = getDeclarationBySymbol(symbol);
return format(declaration?.print() || '', { parser: 'typescript' });
// Four spaces -> two spaces and add a new line at the end
return `${(declaration?.print() || '').replace(/ {4}/g, ' '.repeat(2))}\n`;
}

/**
Expand Down Expand Up @@ -253,7 +253,7 @@ function getDisplayTypeWithLink(
) {
const sourceFile = dummyProject.createSourceFile(
'./dummy.ts',
toSingleLine(escape(originTypeText)),
toSingleLine(originTypeText, config.escapeChars),
{
overwrite: true,
}
Expand Down Expand Up @@ -500,6 +500,7 @@ function generate(
ignoreNestedType(definitionFilePath: string) {
return definitionFilePath.includes('/node_modules/')
},
escapeChars: true,
...config
}

Expand Down
5 changes: 5 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ export type GenerateConfig = {
* When returning true, nested types must not be exported, but when false is returned, nested types may not be exported due to other reasons (such as the nested type has jsdoc @title, which needs to be manually exported)
*/
ignoreNestedType?: (definitionFilePath: string) => boolean;
/*
* Whether to escape characters for extracted type text.
* E.g. `|` will be escaped to `\|`, `<Promise>` will be escaped to `&lt;Promise&gt;`.
*/
escapeChars?: boolean;
};

export type GenerateMarkdownConfig = GenerateConfig & {
Expand Down
12 changes: 8 additions & 4 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export function toSingleLine(str = ''): string {
export function toSingleLine(str = '', escapeChars = true): string {
if (!str) {
return '';
}
return str
.trim()
let newStr = str.trim()
.replace(/[\r\n\t]+/g, '')
.replace(/[\x20]{2,}/g, '')
.replace(/\|/g, '\\|');
if (escapeChars) {
newStr = escape(
newStr.replace(/\|/g, '\\|')
);
}
return newStr;
}

/**
Expand Down

0 comments on commit 1a45f01

Please sign in to comment.