Invoke "prettier . --write" to prettify all source files
This commit is contained in:
Родитель
8fec2c3cab
Коммит
5e8673388d
|
@ -1,10 +1,7 @@
|
|||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
||||
require("@rushstack/eslint-config/patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
"@rushstack/eslint-config/profile/node",
|
||||
"@rushstack/eslint-config/mixins/friendly-locals",
|
||||
],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
extends: ['@rushstack/eslint-config/profile/node', '@rushstack/eslint-config/mixins/friendly-locals'],
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
};
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
|
||||
/**
|
||||
* Returns the average of two numbers.
|
||||
*
|
||||
* @remarks
|
||||
* This method is part of the {@link core-library#Statistics | Statistics subsystem}.
|
||||
* This incomplete HTML tag should be reported as an error: <tag
|
||||
*
|
||||
* @privateRemarks
|
||||
* This content should not show up on the web site.
|
||||
*
|
||||
* @param x - The first input number
|
||||
* @param y - The second input number
|
||||
* @returns The average of `x` and `y`
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
/**
|
||||
* Returns the average of two numbers.
|
||||
*
|
||||
* @remarks
|
||||
* This method is part of the {@link core-library#Statistics | Statistics subsystem}.
|
||||
* This incomplete HTML tag should be reported as an error: <tag
|
||||
*
|
||||
* @privateRemarks
|
||||
* This content should not show up on the web site.
|
||||
*
|
||||
* @param x - The first input number
|
||||
* @param y - The second input number
|
||||
* @returns The average of `x` and `y`
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,6 @@ import { DocNode, DocExcerpt } from '@microsoft/tsdoc';
|
|||
* This is a simplistic solution until we implement proper DocNode rendering APIs.
|
||||
*/
|
||||
export class Formatter {
|
||||
|
||||
public static renderDocNode(docNode: DocNode): string {
|
||||
let result: string = '';
|
||||
if (docNode) {
|
||||
|
|
|
@ -11,39 +11,41 @@ import * as tsdoc from '@microsoft/tsdoc';
|
|||
* https://github.com/Microsoft/TypeScript/blob/v3.0.3/src/compiler/utilities.ts#L6382
|
||||
*/
|
||||
function isDeclarationKind(kind: ts.SyntaxKind): boolean {
|
||||
return kind === ts.SyntaxKind.ArrowFunction
|
||||
|| kind === ts.SyntaxKind.BindingElement
|
||||
|| kind === ts.SyntaxKind.ClassDeclaration
|
||||
|| kind === ts.SyntaxKind.ClassExpression
|
||||
|| kind === ts.SyntaxKind.Constructor
|
||||
|| kind === ts.SyntaxKind.EnumDeclaration
|
||||
|| kind === ts.SyntaxKind.EnumMember
|
||||
|| kind === ts.SyntaxKind.ExportSpecifier
|
||||
|| kind === ts.SyntaxKind.FunctionDeclaration
|
||||
|| kind === ts.SyntaxKind.FunctionExpression
|
||||
|| kind === ts.SyntaxKind.GetAccessor
|
||||
|| kind === ts.SyntaxKind.ImportClause
|
||||
|| kind === ts.SyntaxKind.ImportEqualsDeclaration
|
||||
|| kind === ts.SyntaxKind.ImportSpecifier
|
||||
|| kind === ts.SyntaxKind.InterfaceDeclaration
|
||||
|| kind === ts.SyntaxKind.JsxAttribute
|
||||
|| kind === ts.SyntaxKind.MethodDeclaration
|
||||
|| kind === ts.SyntaxKind.MethodSignature
|
||||
|| kind === ts.SyntaxKind.ModuleDeclaration
|
||||
|| kind === ts.SyntaxKind.NamespaceExportDeclaration
|
||||
|| kind === ts.SyntaxKind.NamespaceImport
|
||||
|| kind === ts.SyntaxKind.Parameter
|
||||
|| kind === ts.SyntaxKind.PropertyAssignment
|
||||
|| kind === ts.SyntaxKind.PropertyDeclaration
|
||||
|| kind === ts.SyntaxKind.PropertySignature
|
||||
|| kind === ts.SyntaxKind.SetAccessor
|
||||
|| kind === ts.SyntaxKind.ShorthandPropertyAssignment
|
||||
|| kind === ts.SyntaxKind.TypeAliasDeclaration
|
||||
|| kind === ts.SyntaxKind.TypeParameter
|
||||
|| kind === ts.SyntaxKind.VariableDeclaration
|
||||
|| kind === ts.SyntaxKind.JSDocTypedefTag
|
||||
|| kind === ts.SyntaxKind.JSDocCallbackTag
|
||||
|| kind === ts.SyntaxKind.JSDocPropertyTag;
|
||||
return (
|
||||
kind === ts.SyntaxKind.ArrowFunction ||
|
||||
kind === ts.SyntaxKind.BindingElement ||
|
||||
kind === ts.SyntaxKind.ClassDeclaration ||
|
||||
kind === ts.SyntaxKind.ClassExpression ||
|
||||
kind === ts.SyntaxKind.Constructor ||
|
||||
kind === ts.SyntaxKind.EnumDeclaration ||
|
||||
kind === ts.SyntaxKind.EnumMember ||
|
||||
kind === ts.SyntaxKind.ExportSpecifier ||
|
||||
kind === ts.SyntaxKind.FunctionDeclaration ||
|
||||
kind === ts.SyntaxKind.FunctionExpression ||
|
||||
kind === ts.SyntaxKind.GetAccessor ||
|
||||
kind === ts.SyntaxKind.ImportClause ||
|
||||
kind === ts.SyntaxKind.ImportEqualsDeclaration ||
|
||||
kind === ts.SyntaxKind.ImportSpecifier ||
|
||||
kind === ts.SyntaxKind.InterfaceDeclaration ||
|
||||
kind === ts.SyntaxKind.JsxAttribute ||
|
||||
kind === ts.SyntaxKind.MethodDeclaration ||
|
||||
kind === ts.SyntaxKind.MethodSignature ||
|
||||
kind === ts.SyntaxKind.ModuleDeclaration ||
|
||||
kind === ts.SyntaxKind.NamespaceExportDeclaration ||
|
||||
kind === ts.SyntaxKind.NamespaceImport ||
|
||||
kind === ts.SyntaxKind.Parameter ||
|
||||
kind === ts.SyntaxKind.PropertyAssignment ||
|
||||
kind === ts.SyntaxKind.PropertyDeclaration ||
|
||||
kind === ts.SyntaxKind.PropertySignature ||
|
||||
kind === ts.SyntaxKind.SetAccessor ||
|
||||
kind === ts.SyntaxKind.ShorthandPropertyAssignment ||
|
||||
kind === ts.SyntaxKind.TypeAliasDeclaration ||
|
||||
kind === ts.SyntaxKind.TypeParameter ||
|
||||
kind === ts.SyntaxKind.VariableDeclaration ||
|
||||
kind === ts.SyntaxKind.JSDocTypedefTag ||
|
||||
kind === ts.SyntaxKind.JSDocCallbackTag ||
|
||||
kind === ts.SyntaxKind.JSDocPropertyTag
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,16 +63,18 @@ function getJSDocCommentRanges(node: ts.Node, text: string): ts.CommentRange[] {
|
|||
case ts.SyntaxKind.FunctionExpression:
|
||||
case ts.SyntaxKind.ArrowFunction:
|
||||
case ts.SyntaxKind.ParenthesizedExpression:
|
||||
commentRanges.push(...ts.getTrailingCommentRanges(text, node.pos) || []);
|
||||
commentRanges.push(...(ts.getTrailingCommentRanges(text, node.pos) || []));
|
||||
break;
|
||||
}
|
||||
commentRanges.push(...ts.getLeadingCommentRanges(text, node.pos) || []);
|
||||
commentRanges.push(...(ts.getLeadingCommentRanges(text, node.pos) || []));
|
||||
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return commentRanges.filter((comment) =>
|
||||
text.charCodeAt(comment.pos + 1) === 0x2A /* ts.CharacterCodes.asterisk */ &&
|
||||
text.charCodeAt(comment.pos + 2) === 0x2A /* ts.CharacterCodes.asterisk */ &&
|
||||
text.charCodeAt(comment.pos + 3) !== 0x2F /* ts.CharacterCodes.slash */);
|
||||
return commentRanges.filter(
|
||||
(comment) =>
|
||||
text.charCodeAt(comment.pos + 1) === 0x2a /* ts.CharacterCodes.asterisk */ &&
|
||||
text.charCodeAt(comment.pos + 2) === 0x2a /* ts.CharacterCodes.asterisk */ &&
|
||||
text.charCodeAt(comment.pos + 3) !== 0x2f /* ts.CharacterCodes.slash */
|
||||
);
|
||||
}
|
||||
|
||||
interface IFoundComment {
|
||||
|
@ -114,7 +118,7 @@ function walkCompilerAstAndFindComments(node: ts.Node, indent: string, foundComm
|
|||
|
||||
console.log(`${indent}- ${ts.SyntaxKind[node.kind]}${foundCommentsSuffix}`);
|
||||
|
||||
return node.forEachChild(child => walkCompilerAstAndFindComments(child, indent + ' ', foundComments));
|
||||
return node.forEachChild((child) => walkCompilerAstAndFindComments(child, indent + ' ', foundComments));
|
||||
}
|
||||
|
||||
function dumpTSDocTree(docNode: tsdoc.DocNode, indent: string): void {
|
||||
|
@ -181,8 +185,8 @@ function parseTSDoc(foundComment: IFoundComment): void {
|
|||
// Since we have the compiler's analysis, use it to calculate the line/column information,
|
||||
// since this is currently faster than TSDoc's TextRange.getLocation() lookup.
|
||||
const location: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(message.textRange.pos);
|
||||
const formattedMessage: string = `${sourceFile.fileName}(${location.line + 1},${location.character + 1}):`
|
||||
+ ` [TSDoc] ${message}`;
|
||||
const formattedMessage: string =
|
||||
`${sourceFile.fileName}(${location.line + 1},${location.character + 1}):` + ` [TSDoc] ${message}`;
|
||||
console.log(formattedMessage);
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +197,7 @@ function parseTSDoc(foundComment: IFoundComment): void {
|
|||
console.log(os.EOL + colors.cyan(`The ${customModifierDefinition.tagName} modifier was NOT FOUND.`));
|
||||
}
|
||||
|
||||
console.log(os.EOL + colors.green('Visiting TSDoc\'s DocNode tree') + os.EOL);
|
||||
console.log(os.EOL + colors.green("Visiting TSDoc's DocNode tree") + os.EOL);
|
||||
dumpTSDocTree(docComment, '');
|
||||
}
|
||||
|
||||
|
@ -206,13 +210,13 @@ export function advancedDemo(): void {
|
|||
|
||||
const inputFilename: string = path.resolve(path.join(__dirname, '..', 'assets', 'advanced-input.ts'));
|
||||
const compilerOptions: ts.CompilerOptions = {
|
||||
'target': ts.ScriptTarget.ES5
|
||||
target: ts.ScriptTarget.ES5
|
||||
};
|
||||
|
||||
// Compile the input
|
||||
console.log('Invoking the TypeScript compiler to analyze assets/advanced-input.ts...');
|
||||
|
||||
const program: ts.Program = ts.createProgram([ inputFilename ], compilerOptions);
|
||||
const program: ts.Program = ts.createProgram([inputFilename], compilerOptions);
|
||||
|
||||
// Report any compiler errors
|
||||
const compilerDiagnostics: ReadonlyArray<ts.Diagnostic> = program.getSemanticDiagnostics();
|
||||
|
@ -220,9 +224,12 @@ export function advancedDemo(): void {
|
|||
for (const diagnostic of compilerDiagnostics) {
|
||||
const message: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, os.EOL);
|
||||
if (diagnostic.file) {
|
||||
const location: ts.LineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
|
||||
const formattedMessage: string = `${diagnostic.file.fileName}(${location.line + 1},${location.character + 1}):`
|
||||
+ ` [TypeScript] ${message}`;
|
||||
const location: ts.LineAndCharacter = diagnostic.file.getLineAndCharacterOfPosition(
|
||||
diagnostic.start!
|
||||
);
|
||||
const formattedMessage: string =
|
||||
`${diagnostic.file.fileName}(${location.line + 1},${location.character + 1}):` +
|
||||
` [TypeScript] ${message}`;
|
||||
console.log(colors.red(formattedMessage));
|
||||
} else {
|
||||
console.log(colors.red(message));
|
||||
|
|
|
@ -27,7 +27,13 @@ export function simpleDemo(): void {
|
|||
console.log(colors.gray('>>>>>>'));
|
||||
|
||||
console.log(os.EOL + colors.green('Extracted Lines:') + os.EOL);
|
||||
console.log(JSON.stringify(parserContext.lines.map(x => x.toString()), undefined, ' '));
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
parserContext.lines.map((x) => x.toString()),
|
||||
undefined,
|
||||
' '
|
||||
)
|
||||
);
|
||||
|
||||
console.log(os.EOL + colors.green('Parser Log Messages:') + os.EOL);
|
||||
|
||||
|
@ -43,24 +49,26 @@ export function simpleDemo(): void {
|
|||
|
||||
const docComment: DocComment = parserContext.docComment;
|
||||
|
||||
console.log(colors.cyan('Summary: ')
|
||||
+ JSON.stringify(Formatter.renderDocNode(docComment.summarySection)));
|
||||
console.log(colors.cyan('Summary: ') + JSON.stringify(Formatter.renderDocNode(docComment.summarySection)));
|
||||
|
||||
if (docComment.remarksBlock) {
|
||||
console.log(colors.cyan('Remarks: ')
|
||||
+ JSON.stringify(Formatter.renderDocNode(docComment.remarksBlock.content)));
|
||||
console.log(
|
||||
colors.cyan('Remarks: ') + JSON.stringify(Formatter.renderDocNode(docComment.remarksBlock.content))
|
||||
);
|
||||
}
|
||||
|
||||
for (const paramBlock of docComment.params.blocks) {
|
||||
console.log(colors.cyan(`Parameter "${paramBlock.parameterName}": `)
|
||||
+ JSON.stringify(Formatter.renderDocNode(paramBlock.content)));
|
||||
console.log(
|
||||
colors.cyan(`Parameter "${paramBlock.parameterName}": `) +
|
||||
JSON.stringify(Formatter.renderDocNode(paramBlock.content))
|
||||
);
|
||||
}
|
||||
|
||||
if (docComment.returnsBlock) {
|
||||
console.log(colors.cyan('Returns: ')
|
||||
+ JSON.stringify(Formatter.renderDocNode(docComment.returnsBlock.content)));
|
||||
console.log(
|
||||
colors.cyan('Returns: ') + JSON.stringify(Formatter.renderDocNode(docComment.returnsBlock.content))
|
||||
);
|
||||
}
|
||||
|
||||
console.log(colors.cyan('Modifiers: ')
|
||||
+ docComment.modifierTagSet.nodes.map(x => x.tagName).join(', '));
|
||||
console.log(colors.cyan('Modifiers: ') + docComment.modifierTagSet.nodes.map((x) => x.tagName).join(', '));
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
variables:
|
||||
FORCE_COLOR: 1
|
||||
jobs:
|
||||
- job: PRBuild
|
||||
condition: succeeded()
|
||||
strategy:
|
||||
maxParallel: 2
|
||||
matrix:
|
||||
'NodeJs 10':
|
||||
NodeVersion: 10
|
||||
'NodeJs 12':
|
||||
NodeVersion: 12
|
||||
steps:
|
||||
- checkout: self
|
||||
- template: templates/build.yaml
|
||||
- job: PRBuild
|
||||
condition: succeeded()
|
||||
strategy:
|
||||
maxParallel: 2
|
||||
matrix:
|
||||
'NodeJs 10':
|
||||
NodeVersion: 10
|
||||
'NodeJs 12':
|
||||
NodeVersion: 12
|
||||
steps:
|
||||
- checkout: self
|
||||
- template: templates/build.yaml
|
||||
|
|
|
@ -4,10 +4,10 @@ variables:
|
|||
NodeVersion: 12
|
||||
FORCE_COLOR: 1
|
||||
steps:
|
||||
- checkout: self
|
||||
persistCredentials: true
|
||||
- template: templates/build.yaml
|
||||
- script: 'node common/scripts/install-run-rush.js version --bump --version-policy BOGUS --target-branch $(Build.SourceBranchName)'
|
||||
displayName: 'Rush Version'
|
||||
- script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --npm-auth-token $(npmToken)'
|
||||
displayName: 'Rush Publish'
|
||||
- checkout: self
|
||||
persistCredentials: true
|
||||
- template: templates/build.yaml
|
||||
- script: 'node common/scripts/install-run-rush.js version --bump --version-policy BOGUS --target-branch $(Build.SourceBranchName)'
|
||||
displayName: 'Rush Version'
|
||||
- script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --npm-auth-token $(npmToken)'
|
||||
displayName: 'Rush Publish'
|
||||
|
|
|
@ -4,8 +4,8 @@ variables:
|
|||
NodeVersion: 12
|
||||
FORCE_COLOR: 1
|
||||
steps:
|
||||
- checkout: self
|
||||
persistCredentials: true
|
||||
- template: templates/build.yaml
|
||||
- script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --npm-auth-token $(npmToken)'
|
||||
displayName: 'Rush Publish'
|
||||
- checkout: self
|
||||
persistCredentials: true
|
||||
- template: templates/build.yaml
|
||||
- script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --npm-auth-token $(npmToken)'
|
||||
displayName: 'Rush Publish'
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
resources:
|
||||
- repo: self
|
||||
- repo: self
|
||||
variables:
|
||||
NodeVersion: 12
|
||||
FORCE_COLOR: 1
|
||||
steps:
|
||||
- checkout: self
|
||||
- template: templates/build.yaml
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Playground Artifacts'
|
||||
inputs:
|
||||
PathtoPublish: playground/dist
|
||||
ArtifactName: playground
|
||||
- checkout: self
|
||||
- template: templates/build.yaml
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Playground Artifacts'
|
||||
inputs:
|
||||
PathtoPublish: playground/dist
|
||||
ArtifactName: playground
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Use Node $(NodeVersion).x'
|
||||
inputs:
|
||||
versionSpec: '$(NodeVersion).x'
|
||||
checkLatest: true
|
||||
- script: 'git config --local user.email rushbot@users.noreply.github.com'
|
||||
displayName: 'git config email'
|
||||
- script: 'git config --local user.name Rushbot'
|
||||
displayName: 'git config name'
|
||||
- script: 'node common/scripts/install-run-rush.js change --verify'
|
||||
displayName: 'Verify Change Logs'
|
||||
- script: 'node common/scripts/install-run-rush.js check'
|
||||
displayName: 'Rush Check'
|
||||
- script: 'node common/scripts/install-run-rush.js install'
|
||||
displayName: 'Rush Install'
|
||||
- script: 'node common/scripts/install-run-rush.js rebuild --verbose --production'
|
||||
displayName: 'Rush Rebuild'
|
||||
- task: NodeTool@0
|
||||
displayName: 'Use Node $(NodeVersion).x'
|
||||
inputs:
|
||||
versionSpec: '$(NodeVersion).x'
|
||||
checkLatest: true
|
||||
- script: 'git config --local user.email rushbot@users.noreply.github.com'
|
||||
displayName: 'git config email'
|
||||
- script: 'git config --local user.name Rushbot'
|
||||
displayName: 'git config name'
|
||||
- script: 'node common/scripts/install-run-rush.js change --verify'
|
||||
displayName: 'Verify Change Logs'
|
||||
- script: 'node common/scripts/install-run-rush.js check'
|
||||
displayName: 'Rush Check'
|
||||
- script: 'node common/scripts/install-run-rush.js install'
|
||||
displayName: 'Rush Install'
|
||||
- script: 'node common/scripts/install-run-rush.js rebuild --verbose --production'
|
||||
displayName: 'Rush Rebuild'
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Rush features. For full documentation, please see https://rushjs.io
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json",
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json"
|
||||
|
||||
/**
|
||||
* Rush 5.14.0 improved incremental builds to ignore spurious changes in the pnpm-lock.json file.
|
||||
|
|
|
@ -27,7 +27,6 @@ module.exports = {
|
|||
* The return value is the updated object.
|
||||
*/
|
||||
function readPackage(packageJson, context) {
|
||||
|
||||
// // The karma types have a missing dependency on typings from the log4js package.
|
||||
// if (packageJson.name === '@types/karma') {
|
||||
// context.log('Fixed up dependencies for @types/karma');
|
||||
|
|
|
@ -20,21 +20,21 @@
|
|||
// * SemVer range is usually restricted to a single version.
|
||||
// */
|
||||
// "definitionName": "lockStepVersion",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Required) The name that will be used for the "versionPolicyName" field in rush.json.
|
||||
// * This name is also used command-line parameters such as "--version-policy"
|
||||
// * and "--to-version-policy".
|
||||
// */
|
||||
// "policyName": "MyBigFramework",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Required) The current version. All packages belonging to the set should have this version
|
||||
// * in the current branch. When bumping versions, Rush uses this to determine the next version.
|
||||
// * (The "version" field in package.json is NOT considered.)
|
||||
// */
|
||||
// "version": "1.0.0",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Required) The type of bump that will be performed when publishing the next release.
|
||||
// * When creating a release branch in Git, this field should be updated according to the
|
||||
|
@ -43,7 +43,7 @@
|
|||
// * Valid values are: "prerelease", "release", "minor", "patch", "major"
|
||||
// */
|
||||
// "nextBump": "prerelease",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Optional) If specified, all packages in the set share a common CHANGELOG.md file.
|
||||
// * This file is stored with the specified "main" project, which must be a member of the set.
|
||||
|
@ -53,7 +53,7 @@
|
|||
// */
|
||||
// "mainProject": "my-app"
|
||||
// },
|
||||
//
|
||||
//
|
||||
// {
|
||||
// /**
|
||||
// * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion").
|
||||
|
@ -66,9 +66,9 @@
|
|||
// * is changed.
|
||||
// */
|
||||
// "definitionName": "individualVersion",
|
||||
//
|
||||
//
|
||||
// "policyName": "MyRandomLibraries",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Optional) This can be used to enforce that all packages in the set must share a common
|
||||
// * major version number, e.g. because they are from the same major release branch.
|
||||
|
@ -77,7 +77,7 @@
|
|||
// * to the types of changes made to each project, according to the "rush change" command.
|
||||
// */
|
||||
// "lockedMajor": 3,
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * (Optional) When publishing is managed by Rush, by default the "rush change" command will
|
||||
// * request changes for any projects that are modified by a pull request. These change entries
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
||||
require("@rushstack/eslint-config/patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
"@rushstack/eslint-config/profile/node",
|
||||
"@rushstack/eslint-config/mixins/friendly-locals",
|
||||
],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
extends: ['@rushstack/eslint-config/profile/node', '@rushstack/eslint-config/mixins/friendly-locals'],
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ export class ConfigCache {
|
|||
|
||||
// If configFilePath is an empty string, then we'll use the folder of sourceFilePath as our cache key
|
||||
// (instead of an empty string)
|
||||
const cacheKey: string = configFilePath || (sourceFileFolder + '/');
|
||||
const cacheKey: string = configFilePath || sourceFileFolder + '/';
|
||||
Debug.log(`Cache key: "${cacheKey}"`);
|
||||
|
||||
const nowMs: number = ConfigCache._getTimeInMs();
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
export class Debug {
|
||||
// To debug the plugin, temporarily uncomment the body of this function
|
||||
public static log(message: string): void {
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import * as eslint from "eslint";
|
||||
import * as ESTree from "estree";
|
||||
import {
|
||||
TSDocParser,
|
||||
TextRange,
|
||||
TSDocConfiguration,
|
||||
ParserContext
|
||||
} from "@microsoft/tsdoc";
|
||||
import * as eslint from 'eslint';
|
||||
import * as ESTree from 'estree';
|
||||
import { TSDocParser, TextRange, TSDocConfiguration, ParserContext } from '@microsoft/tsdoc';
|
||||
import { TSDocConfigFile } from '@microsoft/tsdoc-config';
|
||||
|
||||
import { Debug } from './Debug';
|
||||
import { ConfigCache } from './ConfigCache';
|
||||
|
||||
const tsdocMessageIds: {[x: string]: string} = {};
|
||||
const tsdocMessageIds: { [x: string]: string } = {};
|
||||
|
||||
const defaultTSDocConfiguration: TSDocConfiguration = new TSDocConfiguration();
|
||||
defaultTSDocConfiguration.allTsdocMessageIds.forEach((messageId: string) => {
|
||||
|
@ -19,34 +14,34 @@ defaultTSDocConfiguration.allTsdocMessageIds.forEach((messageId: string) => {
|
|||
});
|
||||
|
||||
interface IPlugin {
|
||||
rules: {[x: string]: eslint.Rule.RuleModule};
|
||||
rules: { [x: string]: eslint.Rule.RuleModule };
|
||||
}
|
||||
|
||||
const plugin: IPlugin = {
|
||||
rules: {
|
||||
// NOTE: The actual ESLint rule name will be "tsdoc/syntax". It is calculated by deleting "eslint-plugin-"
|
||||
// from the NPM package name, and then appending this string.
|
||||
"syntax": {
|
||||
syntax: {
|
||||
meta: {
|
||||
messages: {
|
||||
"error-loading-config-file": "Error loading TSDoc config file:\n{{details}}",
|
||||
"error-applying-config": "Error applying TSDoc configuration: {{details}}",
|
||||
'error-loading-config-file': 'Error loading TSDoc config file:\n{{details}}',
|
||||
'error-applying-config': 'Error applying TSDoc configuration: {{details}}',
|
||||
...tsdocMessageIds
|
||||
},
|
||||
type: "problem",
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: "Validates that TypeScript documentation comments conform to the TSDoc standard",
|
||||
category: "Stylistic Issues",
|
||||
description: 'Validates that TypeScript documentation comments conform to the TSDoc standard',
|
||||
category: 'Stylistic Issues',
|
||||
// This package is experimental
|
||||
recommended: false,
|
||||
url: "https://github.com/microsoft/tsdoc/blob/master/eslint-plugin/README.md"
|
||||
url: 'https://github.com/microsoft/tsdoc/blob/master/eslint-plugin/README.md'
|
||||
}
|
||||
},
|
||||
create: (context: eslint.Rule.RuleContext) => {
|
||||
const sourceFilePath: string = context.getFilename();
|
||||
Debug.log(`Linting: "${sourceFilePath}"`);
|
||||
|
||||
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration()
|
||||
const tsdocConfiguration: TSDocConfiguration = new TSDocConfiguration();
|
||||
|
||||
try {
|
||||
const tsdocConfigFile: TSDocConfigFile = ConfigCache.getForSourceFile(sourceFilePath);
|
||||
|
@ -54,7 +49,7 @@ const plugin: IPlugin = {
|
|||
if (tsdocConfigFile.hasErrors) {
|
||||
context.report({
|
||||
loc: { line: 1, column: 1 },
|
||||
messageId: "error-loading-config-file",
|
||||
messageId: 'error-loading-config-file',
|
||||
data: {
|
||||
details: tsdocConfigFile.getErrorSummary()
|
||||
}
|
||||
|
@ -66,7 +61,7 @@ const plugin: IPlugin = {
|
|||
} catch (e) {
|
||||
context.report({
|
||||
loc: { line: 1, column: 1 },
|
||||
messageId: "error-applying-config",
|
||||
messageId: 'error-applying-config',
|
||||
data: {
|
||||
details: e.message
|
||||
}
|
||||
|
@ -76,7 +71,7 @@ const plugin: IPlugin = {
|
|||
} catch (e) {
|
||||
context.report({
|
||||
loc: { line: 1, column: 1 },
|
||||
messageId: "error-loading-config-file",
|
||||
messageId: 'error-loading-config-file',
|
||||
data: {
|
||||
details: `Unexpected exception: ${e.message}`
|
||||
}
|
||||
|
@ -88,14 +83,18 @@ const plugin: IPlugin = {
|
|||
const sourceCode: eslint.SourceCode = context.getSourceCode();
|
||||
const checkCommentBlocks: (node: ESTree.Node) => void = function (node: ESTree.Node) {
|
||||
for (const comment of sourceCode.getAllComments()) {
|
||||
if (comment.type !== "Block") {
|
||||
if (comment.type !== 'Block') {
|
||||
continue;
|
||||
}
|
||||
if (!comment.range) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const textRange: TextRange = TextRange.fromStringRange(sourceCode.text, comment.range[0], comment.range[1]);
|
||||
const textRange: TextRange = TextRange.fromStringRange(
|
||||
sourceCode.text,
|
||||
comment.range[0],
|
||||
comment.range[1]
|
||||
);
|
||||
|
||||
// Smallest comment is "/***/"
|
||||
if (textRange.length < 5) {
|
||||
|
@ -120,7 +119,7 @@ const plugin: IPlugin = {
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
Program: checkCommentBlocks
|
||||
|
@ -128,6 +127,6 @@ const plugin: IPlugin = {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export = plugin;
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import { RuleTester } from "eslint";
|
||||
import * as plugin from "../index";
|
||||
import { RuleTester } from 'eslint';
|
||||
import * as plugin from '../index';
|
||||
|
||||
const ruleTester: RuleTester = new RuleTester({
|
||||
env: {
|
||||
es6: true,
|
||||
},
|
||||
es6: true
|
||||
}
|
||||
});
|
||||
ruleTester.run('"tsdoc/syntax" rule', plugin.rules.syntax, {
|
||||
valid: [
|
||||
"/**\nA great function!\n */\nfunction foobar() {}\n",
|
||||
"/**\nA great class!\n */\nclass FooBar {}\n",
|
||||
'/**\nA great function!\n */\nfunction foobar() {}\n',
|
||||
'/**\nA great class!\n */\nclass FooBar {}\n'
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: "/**\n * This `is wrong\n */\nfunction foobar() {}\n",
|
||||
code: '/**\n * This `is wrong\n */\nfunction foobar() {}\n',
|
||||
errors: [
|
||||
{
|
||||
messageId: "tsdoc-code-span-missing-delimiter",
|
||||
},
|
||||
],
|
||||
messageId: 'tsdoc-code-span-missing-delimiter'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
code: "/**\n * This `is wrong\n */\nclass FooBar {}\n",
|
||||
code: '/**\n * This `is wrong\n */\nclass FooBar {}\n',
|
||||
errors: [
|
||||
{
|
||||
messageId: "tsdoc-code-span-missing-delimiter",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
messageId: 'tsdoc-code-span-missing-delimiter'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
||||
require("@rushstack/eslint-config/patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
"@rushstack/eslint-config/profile/web-app",
|
||||
"@rushstack/eslint-config/mixins/friendly-locals",
|
||||
"@rushstack/eslint-config/mixins/react",
|
||||
'@rushstack/eslint-config/profile/web-app',
|
||||
'@rushstack/eslint-config/mixins/friendly-locals',
|
||||
'@rushstack/eslint-config/mixins/react'
|
||||
],
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: "16.9",
|
||||
},
|
||||
version: '16.9'
|
||||
}
|
||||
},
|
||||
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
};
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
"staticAssetsToCopy": {
|
||||
"fileExtensions": [".json", ".css"],
|
||||
"includeGlobs": [ "samples/*.ts" ]
|
||||
"includeGlobs": ["samples/*.ts"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import { PlaygroundView } from './PlaygroundView';
|
|||
|
||||
class App extends React.Component {
|
||||
public render(): React.ReactNode {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PlaygroundView />
|
||||
|
|
|
@ -51,7 +51,7 @@ export interface ICodeEditorState {
|
|||
interface IMonacoWindow extends Window {
|
||||
require: {
|
||||
(paths: string[], callback: (monaco: typeof monacoEditor) => void): void;
|
||||
config: (options: { paths: { [name: string]: string } }) => void
|
||||
config: (options: { paths: { [name: string]: string } }) => void;
|
||||
};
|
||||
MonacoEnvironment: {
|
||||
getWorkerUrl: (workerId: string, label: string) => void;
|
||||
|
@ -68,11 +68,11 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
|
||||
private _existingSyntaxStyles: { [hash: string]: string } = {};
|
||||
private _editorId: string;
|
||||
private _isMounted: boolean=false;
|
||||
private _isMounted: boolean = false;
|
||||
private _editor: monacoEditor.editor.IStandaloneCodeEditor | undefined;
|
||||
|
||||
private _placeholderDivRef: HTMLDivElement | undefined;
|
||||
private _hostDivRef: HTMLDivElement | undefined;
|
||||
private _hostDivRef: HTMLDivElement | undefined;
|
||||
|
||||
public constructor(props: ICodeEditorProps) {
|
||||
super(props);
|
||||
|
@ -105,17 +105,17 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
private static _initializeMonaco(): Promise<typeof monacoEditor> {
|
||||
if (!CodeEditor._initializePromise) {
|
||||
CodeEditor._initializePromise = new Promise(
|
||||
(resolve: (monaco: typeof monacoEditor) => void, reject: (error: Error) => void ) => {
|
||||
const monacoWindow: IMonacoWindow = window as unknown as IMonacoWindow;
|
||||
monacoWindow.require.config({ paths: { 'vs': `${MONACO_BASE_URL}vs/` }});
|
||||
(resolve: (monaco: typeof monacoEditor) => void, reject: (error: Error) => void) => {
|
||||
const monacoWindow: IMonacoWindow = (window as unknown) as IMonacoWindow;
|
||||
monacoWindow.require.config({ paths: { vs: `${MONACO_BASE_URL}vs/` } });
|
||||
|
||||
monacoWindow.MonacoEnvironment = {
|
||||
getWorkerUrl: (workerId, label) => {
|
||||
return `data:text/javascript;charset=utf-8,${encodeURIComponent(
|
||||
'self.MonacoEnvironment = {' +
|
||||
`baseUrl: '${MONACO_BASE_URL}'` +
|
||||
'};' +
|
||||
`importScripts('${MONACO_BASE_URL}vs/base/worker/workerMain.js');`
|
||||
'};' +
|
||||
`importScripts('${MONACO_BASE_URL}vs/base/worker/workerMain.js');`
|
||||
)}`;
|
||||
}
|
||||
};
|
||||
|
@ -139,14 +139,16 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
|
||||
public componentDidMount(): void {
|
||||
this._isMounted = true;
|
||||
CodeEditor._initializeMonaco().then((monaco) => {
|
||||
this.setState({ monaco });
|
||||
if (this._isMounted) {
|
||||
window.addEventListener('resize', this._onWindowResize);
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.setState({ monacoErrorMessage: `Error loading Monaco editor: ${error}` });
|
||||
});
|
||||
CodeEditor._initializeMonaco()
|
||||
.then((monaco) => {
|
||||
this.setState({ monaco });
|
||||
if (this._isMounted) {
|
||||
window.addEventListener('resize', this._onWindowResize);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({ monacoErrorMessage: `Error loading Monaco editor: ${error}` });
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
|
@ -201,26 +203,26 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
public render(): React.ReactNode {
|
||||
if (this.state.monacoErrorMessage) {
|
||||
return (
|
||||
<FlexColDiv
|
||||
className={ this.props.className }
|
||||
style={ this.props.style } >
|
||||
{ this.state.monacoErrorMessage }
|
||||
<FlexColDiv className={this.props.className} style={this.props.style}>
|
||||
{this.state.monacoErrorMessage}
|
||||
</FlexColDiv>
|
||||
);
|
||||
);
|
||||
} else {
|
||||
// The Monaco application is very complex and its div does not resize reliably.
|
||||
// To work around this, we render a blank placeholder div (that is well-behaved),
|
||||
// and then the Monaco host div floats above that using absolute positioning
|
||||
// and manual resizing.
|
||||
return (
|
||||
<div className='playground-monaco-placeholder'
|
||||
ref={ this._onRefPlaceholder }
|
||||
style={ { display: 'flex', flexDirection: 'column', flex: 1, ...this.props.style } }>
|
||||
|
||||
<div className='playground-monaco-host'
|
||||
ref={ this._onRefHost }
|
||||
style={ { display: 'block', position: 'absolute', backgroundColor: '#00FF00' } } />
|
||||
|
||||
<div
|
||||
className="playground-monaco-placeholder"
|
||||
ref={this._onRefPlaceholder}
|
||||
style={{ display: 'flex', flexDirection: 'column', flex: 1, ...this.props.style }}
|
||||
>
|
||||
<div
|
||||
className="playground-monaco-host"
|
||||
ref={this._onRefHost}
|
||||
style={{ display: 'block', position: 'absolute', backgroundColor: '#00FF00' }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -230,8 +232,9 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
this._placeholderDivRef = element;
|
||||
}
|
||||
|
||||
private _onRefHost(element: HTMLDivElement): void{
|
||||
this._hostDivRef = element; this._createEditor();
|
||||
private _onRefHost(element: HTMLDivElement): void {
|
||||
this._hostDivRef = element;
|
||||
this._createEditor();
|
||||
}
|
||||
|
||||
private _applySyntaxStyling(newSyntaxStyles: IStyledRange[]): void {
|
||||
|
@ -262,8 +265,9 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
}
|
||||
|
||||
this._getEditorModel().deltaDecorations(decorationsToRemove, []);
|
||||
const decorationIds: string[] = this._getEditorModel().deltaDecorations([], decorationsToAdd.map(
|
||||
(decoration) => {
|
||||
const decorationIds: string[] = this._getEditorModel().deltaDecorations(
|
||||
[],
|
||||
decorationsToAdd.map((decoration) => {
|
||||
const startPos: monacoEditor.Position = this._getEditorModel().getPositionAt(decoration.pos);
|
||||
const endPos: monacoEditor.Position = this._getEditorModel().getPositionAt(decoration.end);
|
||||
|
||||
|
@ -280,8 +284,8 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
inlineClassName: decoration.className
|
||||
}
|
||||
};
|
||||
}
|
||||
));
|
||||
})
|
||||
);
|
||||
|
||||
for (let i: number = 0; i < decorationsToAdd.length; i++) {
|
||||
newExistingSyntaxStyles[hashesOfDecorationsToAdd[i]] = decorationIds[i];
|
||||
|
@ -302,11 +306,10 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
}
|
||||
|
||||
private _createEditor(): void {
|
||||
CodeEditor._initializeMonaco().then((monaco) => {
|
||||
if (!this._editor && this._hostDivRef) {
|
||||
this._editor = monaco.editor.create(
|
||||
this._hostDivRef,
|
||||
{
|
||||
CodeEditor._initializeMonaco()
|
||||
.then((monaco) => {
|
||||
if (!this._editor && this._hostDivRef) {
|
||||
this._editor = monaco.editor.create(this._hostDivRef, {
|
||||
value: this.props.value || '',
|
||||
language: this.props.language,
|
||||
readOnly: this.props.readOnly,
|
||||
|
@ -316,20 +319,20 @@ export class CodeEditor extends React.Component<ICodeEditorProps, ICodeEditorSta
|
|||
lineNumbers: this.props.disableLineNumbers ? 'off' : 'on',
|
||||
theme: this.props.theme,
|
||||
wordWrap: this.props.wordWrap ? 'on' : 'off'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
this._getEditorModel().onDidChangeContent((e) => {
|
||||
if (this._editor) {
|
||||
this._safeOnChange(this._editor.getValue());
|
||||
}
|
||||
});
|
||||
this._getEditorModel().onDidChangeContent((e) => {
|
||||
if (this._editor) {
|
||||
this._safeOnChange(this._editor.getValue());
|
||||
}
|
||||
});
|
||||
|
||||
this._onWindowResize();
|
||||
}
|
||||
}).catch((e) => {
|
||||
console.error('CodeEditor._createEditor() failed: ' + e.toString());
|
||||
});
|
||||
this._onWindowResize();
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('CodeEditor._createEditor() failed: ' + e.toString());
|
||||
});
|
||||
}
|
||||
|
||||
private _onWindowResize(): void {
|
||||
|
|
|
@ -19,11 +19,11 @@ export class DocAstView extends React.Component<IDocAstViewProps> {
|
|||
|
||||
return (
|
||||
<CodeEditor
|
||||
className='playground-ast-text-editor'
|
||||
readOnly={ true }
|
||||
value={ outputLines.join('\n') }
|
||||
disableLineNumbers={ true }
|
||||
theme={ this.props.theme }
|
||||
className="playground-ast-text-editor"
|
||||
readOnly={true}
|
||||
value={outputLines.join('\n')}
|
||||
disableLineNumbers={true}
|
||||
theme={this.props.theme}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,19 +23,19 @@ export class DocDomView extends React.Component<IDocDomViewProps> {
|
|||
|
||||
if (parserContext && parserContext.docComment) {
|
||||
const unindentedCode: string = ReactDomServer.renderToStaticMarkup(
|
||||
<DocHtmlView docComment={ parserContext.docComment } />
|
||||
<DocHtmlView docComment={parserContext.docComment} />
|
||||
);
|
||||
code = this._indentHtml(unindentedCode);
|
||||
}
|
||||
|
||||
return (
|
||||
<CodeEditor
|
||||
className='playground-dom-text-editor'
|
||||
readOnly={ true }
|
||||
value={ code }
|
||||
language='html'
|
||||
disableLineNumbers={ true }
|
||||
theme={ this.props.theme }
|
||||
className="playground-dom-text-editor"
|
||||
readOnly={true}
|
||||
value={code}
|
||||
language="html"
|
||||
disableLineNumbers={true}
|
||||
theme={this.props.theme}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
// Summary
|
||||
if (docComment.summarySection) {
|
||||
outputElements.push(
|
||||
<React.Fragment key='summary'>
|
||||
<h2 className='doc-heading'>Summary</h2>
|
||||
{ this._renderContainer(docComment.summarySection) }
|
||||
<React.Fragment key="summary">
|
||||
<h2 className="doc-heading">Summary</h2>
|
||||
{this._renderContainer(docComment.summarySection)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -29,25 +29,23 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
for (const paramBlock of docComment.params.blocks) {
|
||||
rows.push(
|
||||
<tr key={`param_${rows.length}`}>
|
||||
<td>{ paramBlock.parameterName }</td>
|
||||
<td>{ this._renderContainer(paramBlock.content) }</td>
|
||||
<td>{paramBlock.parameterName}</td>
|
||||
<td>{this._renderContainer(paramBlock.content)}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
outputElements.push(
|
||||
<React.Fragment key='parameters'>
|
||||
<h2 className='doc-heading'>Parameters</h2>
|
||||
<table className='doc-table'>
|
||||
<React.Fragment key="parameters">
|
||||
<h2 className="doc-heading">Parameters</h2>
|
||||
<table className="doc-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
<tbody>{rows}</tbody>
|
||||
</table>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
@ -56,33 +54,34 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
// Returns
|
||||
if (docComment.returnsBlock) {
|
||||
outputElements.push(
|
||||
<React.Fragment key='returns'>
|
||||
<h2 className='doc-heading'>Return Value</h2>
|
||||
{ this._renderContainer(docComment.returnsBlock.content) }
|
||||
<React.Fragment key="returns">
|
||||
<h2 className="doc-heading">Return Value</h2>
|
||||
{this._renderContainer(docComment.returnsBlock.content)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
if (docComment.remarksBlock) {
|
||||
outputElements.push(
|
||||
<React.Fragment key='remarks'>
|
||||
<h2 className='doc-heading'>Remarks</h2>
|
||||
{ this._renderContainer(docComment.remarksBlock.content) }
|
||||
<React.Fragment key="remarks">
|
||||
<h2 className="doc-heading">Remarks</h2>
|
||||
{this._renderContainer(docComment.remarksBlock.content)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const exampleBlocks: tsdoc.DocBlock[] = docComment.customBlocks.filter(x => x.blockTag.tagNameWithUpperCase
|
||||
=== tsdoc.StandardTags.example.tagNameWithUpperCase);
|
||||
const exampleBlocks: tsdoc.DocBlock[] = docComment.customBlocks.filter(
|
||||
(x) => x.blockTag.tagNameWithUpperCase === tsdoc.StandardTags.example.tagNameWithUpperCase
|
||||
);
|
||||
|
||||
let exampleNumber: number = 1;
|
||||
for (const exampleBlock of exampleBlocks) {
|
||||
const heading: string = exampleBlocks.length > 1 ? `Example ${exampleNumber}` : 'Example';
|
||||
|
||||
outputElements.push(
|
||||
<React.Fragment key='seeAlso'>
|
||||
<h2 className='doc-heading'>{heading}</h2>
|
||||
{ this._renderContainer(exampleBlock.content) }
|
||||
<React.Fragment key="seeAlso">
|
||||
<h2 className="doc-heading">{heading}</h2>
|
||||
{this._renderContainer(exampleBlock.content)}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
|
@ -92,19 +91,13 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
if (docComment.seeBlocks.length > 0) {
|
||||
const listItems: React.ReactNode[] = [];
|
||||
for (const seeBlock of docComment.seeBlocks) {
|
||||
listItems.push(
|
||||
<li key={`item_${listItems.length}`}>
|
||||
{ this._renderContainer(seeBlock.content) }
|
||||
</li>
|
||||
);
|
||||
listItems.push(<li key={`item_${listItems.length}`}>{this._renderContainer(seeBlock.content)}</li>);
|
||||
}
|
||||
|
||||
outputElements.push(
|
||||
<React.Fragment key='seeAlso'>
|
||||
<h2 className='doc-heading'>See Also</h2>
|
||||
<ul>
|
||||
{listItems}
|
||||
</ul>
|
||||
<React.Fragment key="seeAlso">
|
||||
<h2 className="doc-heading">See Also</h2>
|
||||
<ul>{listItems}</ul>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -118,21 +111,21 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
const key: string = `modifier_${modifierElements.length}`;
|
||||
modifierElements.push(
|
||||
<React.Fragment key={key}>
|
||||
{ ' ' }
|
||||
<code className='doc-code-span'>{ modifierTag.tagName }</code>
|
||||
{' '}
|
||||
<code className="doc-code-span">{modifierTag.tagName}</code>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
outputElements.push(
|
||||
<React.Fragment key='modifiers'>
|
||||
<h2 className='doc-heading'>Modifiers</h2>
|
||||
{ modifierElements }
|
||||
<React.Fragment key="modifiers">
|
||||
<h2 className="doc-heading">Modifiers</h2>
|
||||
{modifierElements}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return <div style={ this.props.style }> {outputElements} </div>;
|
||||
return <div style={this.props.style}> {outputElements} </div>;
|
||||
}
|
||||
|
||||
private _renderContainer(section: tsdoc.DocNodeContainer): React.ReactNode {
|
||||
|
@ -141,13 +134,17 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
const key: string = `key_${elements.length}`;
|
||||
elements.push(this._renderDocNode(node, key));
|
||||
}
|
||||
return (<React.Fragment>{elements}</React.Fragment> );
|
||||
return <React.Fragment>{elements}</React.Fragment>;
|
||||
}
|
||||
|
||||
private _renderDocNode(node: tsdoc.DocNode, key: string): React.ReactNode | undefined {
|
||||
switch (node.kind) {
|
||||
case 'CodeSpan':
|
||||
return <code key={key} className='doc-code-span'>{(node as tsdoc.DocCodeSpan).code}</code>;
|
||||
return (
|
||||
<code key={key} className="doc-code-span">
|
||||
{(node as tsdoc.DocCodeSpan).code}
|
||||
</code>
|
||||
);
|
||||
case 'ErrorText':
|
||||
return <React.Fragment key={key}>{(node as tsdoc.DocErrorText).text}</React.Fragment>;
|
||||
case 'EscapedText':
|
||||
|
@ -155,10 +152,8 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
case 'FencedCode':
|
||||
const docFencedCode: tsdoc.DocFencedCode = node as tsdoc.DocFencedCode;
|
||||
return (
|
||||
<pre key={key} className='doc-fenced-code'>
|
||||
<code key={key}>
|
||||
{ docFencedCode.code }
|
||||
</code>
|
||||
<pre key={key} className="doc-fenced-code">
|
||||
<code key={key}>{docFencedCode.code}</code>
|
||||
</pre>
|
||||
);
|
||||
break;
|
||||
|
@ -166,35 +161,43 @@ export class DocHtmlView extends React.Component<IDocHtmlViewProps> {
|
|||
const linkTag: tsdoc.DocLinkTag = node as tsdoc.DocLinkTag;
|
||||
if (linkTag.urlDestination) {
|
||||
const linkText: string = linkTag.linkText || linkTag.urlDestination;
|
||||
return <a key={key} href='#'>{linkText}</a>;
|
||||
return (
|
||||
<a key={key} href="#">
|
||||
{linkText}
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
let identifier: string = '';
|
||||
if (linkTag.codeDestination) {
|
||||
// TODO: The library should provide a default rendering for this
|
||||
const memberReferences: ReadonlyArray<tsdoc.DocMemberReference> = linkTag.codeDestination.memberReferences;
|
||||
const memberReferences: ReadonlyArray<tsdoc.DocMemberReference> =
|
||||
linkTag.codeDestination.memberReferences;
|
||||
if (memberReferences.length > 0) {
|
||||
const memberIdentifier: tsdoc.DocMemberIdentifier | undefined
|
||||
= memberReferences[memberReferences.length - 1].memberIdentifier;
|
||||
const memberIdentifier: tsdoc.DocMemberIdentifier | undefined =
|
||||
memberReferences[memberReferences.length - 1].memberIdentifier;
|
||||
if (memberIdentifier) {
|
||||
identifier = memberIdentifier.identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
const linkText: string = linkTag.linkText || identifier || '???';
|
||||
return <a key={key} href='#'>{linkText}</a>;
|
||||
return (
|
||||
<a key={key} href="#">
|
||||
{linkText}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
case 'Paragraph':
|
||||
// Collapse spaces in the paragraph
|
||||
const transformedParagraph: tsdoc.DocParagraph = tsdoc.DocNodeTransforms.trimSpacesInParagraph(
|
||||
node as tsdoc.DocParagraph);
|
||||
|
||||
return (
|
||||
<p key={key}>{ this._renderContainer(transformedParagraph) }</p>
|
||||
node as tsdoc.DocParagraph
|
||||
);
|
||||
|
||||
return <p key={key}>{this._renderContainer(transformedParagraph)}</p>;
|
||||
case 'PlainText':
|
||||
return <React.Fragment key={key}>{(node as tsdoc.DocPlainText).text}</React.Fragment>;
|
||||
case 'SoftBreak':
|
||||
return <React.Fragment key={key}>{' '}</React.Fragment>;
|
||||
return <React.Fragment key={key}> </React.Fragment>;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export interface IFlexDivProps extends React.DetailedHTMLProps<
|
||||
React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
||||
}
|
||||
|
||||
export class FlexRowDiv extends React.Component<IFlexDivProps> {
|
||||
export interface IFlexDivProps
|
||||
extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {}
|
||||
|
||||
export class FlexRowDiv extends React.Component<IFlexDivProps> {
|
||||
public render(): React.ReactNode {
|
||||
const mergedProps: IFlexDivProps = {
|
||||
...this.props
|
||||
};
|
||||
|
||||
if (mergedProps.style === undefined) {
|
||||
mergedProps.style = { };
|
||||
mergedProps.style = {};
|
||||
}
|
||||
if (mergedProps.style.display === undefined) {
|
||||
mergedProps.style.display = 'flex';
|
||||
|
@ -23,18 +21,16 @@ export class FlexRowDiv extends React.Component<IFlexDivProps> {
|
|||
|
||||
return React.createElement('div', mergedProps);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FlexColDiv extends React.Component<IFlexDivProps> {
|
||||
|
||||
export class FlexColDiv extends React.Component<IFlexDivProps> {
|
||||
public render(): React.ReactNode {
|
||||
const mergedProps: IFlexDivProps = {
|
||||
...this.props
|
||||
};
|
||||
|
||||
if (mergedProps.style === undefined) {
|
||||
mergedProps.style = { };
|
||||
mergedProps.style = {};
|
||||
}
|
||||
if (mergedProps.style.display === undefined) {
|
||||
mergedProps.style.display = 'flex';
|
||||
|
@ -45,5 +41,4 @@ export class FlexColDiv extends React.Component<IFlexDivProps> {
|
|||
|
||||
return React.createElement('div', mergedProps);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,21 +6,15 @@ import { FlexRowDiv, FlexColDiv } from './FlexDivs';
|
|||
import { DocHtmlView } from './DocHtmlView';
|
||||
import { DocDomView } from './DocDomView';
|
||||
import { DocAstView } from './DocAstView';
|
||||
import {
|
||||
CodeEditor,
|
||||
ISyntaxMarker,
|
||||
IStyledRange
|
||||
} from './CodeEditor';
|
||||
import { CodeEditor, ISyntaxMarker, IStyledRange } from './CodeEditor';
|
||||
import { DocNodeSyntaxStyler } from './SyntaxStyler/DocNodeSyntaxStyler';
|
||||
import { SampleInputs } from './samples/SampleInputs';
|
||||
|
||||
export const enum Theme {
|
||||
vs = 'vs'
|
||||
|
||||
}
|
||||
|
||||
export interface IPlaygroundViewProps {
|
||||
}
|
||||
export interface IPlaygroundViewProps {}
|
||||
|
||||
export interface IPlaygroundViewState {
|
||||
inputText: string;
|
||||
|
@ -30,7 +24,7 @@ export interface IPlaygroundViewState {
|
|||
selectedTheme: string;
|
||||
}
|
||||
|
||||
export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlaygroundViewState> {
|
||||
export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlaygroundViewState> {
|
||||
private readonly _textAreaStyle: React.CSSProperties = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -58,7 +52,7 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
|
||||
this._inputTextArea_onChange = this._inputTextArea_onChange.bind(this);
|
||||
this._selectSample_onChange = this._selectSample_onChange.bind(this);
|
||||
this._selectTheme_onChange = this._selectTheme_onChange.bind(this)
|
||||
this._selectTheme_onChange = this._selectTheme_onChange.bind(this);
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
|
@ -109,38 +103,43 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
};
|
||||
|
||||
return (
|
||||
<FlexColDiv className='playground-frame' style={ { flex: 1 } }>
|
||||
<FlexRowDiv className='playground-header' style={ headerStyle }>
|
||||
<FlexColDiv className="playground-frame" style={{ flex: 1 }}>
|
||||
<FlexRowDiv className="playground-header" style={headerStyle}>
|
||||
<FlexColDiv style={{ fontWeight: 400, fontSize: '26px' }}>TSDoc Playground</FlexColDiv>
|
||||
<FlexColDiv style={{ fontWeight: 400, fontSize: '20px' }}>
|
||||
<a style={navAnchorStyle} href='https://github.com/Microsoft/tsdoc' target='_blank'
|
||||
rel='noopener noreferrer'>
|
||||
What is TSDoc?</a>
|
||||
<a
|
||||
style={navAnchorStyle}
|
||||
href="https://github.com/Microsoft/tsdoc"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
What is TSDoc?
|
||||
</a>
|
||||
</FlexColDiv>
|
||||
</FlexRowDiv>
|
||||
|
||||
<FlexColDiv className='playground-content-area' style={ { margin: '4px', flex: 1 } }>
|
||||
<FlexRowDiv className='playground-main-row' style={ mainRowStyle }>
|
||||
{ this._renderInputBox() }
|
||||
<FlexColDiv className="playground-content-area" style={{ margin: '4px', flex: 1 }}>
|
||||
<FlexRowDiv className="playground-main-row" style={mainRowStyle}>
|
||||
{this._renderInputBox()}
|
||||
|
||||
<TabPane
|
||||
style={ { flex: 1, marginLeft: '4px' } }
|
||||
buttonRowStyle={ { height: '40px', boxSizing: 'border-box' } }
|
||||
tabs={ [
|
||||
style={{ flex: 1, marginLeft: '4px' }}
|
||||
buttonRowStyle={{ height: '40px', boxSizing: 'border-box' }}
|
||||
tabs={[
|
||||
{ title: 'HTML', render: this._renderHtml.bind(this) },
|
||||
{ title: 'DOM', render: this._renderDom.bind(this) },
|
||||
{ title: 'Lines', render: this._renderLines.bind(this) },
|
||||
{ title: 'AST', render: this._renderAst.bind(this) },
|
||||
{ title: 'Emitter', render: this._renderEmitter.bind(this) }
|
||||
] }
|
||||
]}
|
||||
/>
|
||||
</FlexRowDiv>
|
||||
<FlexColDiv className='playground-errors-pane' style={ errorsPaneStyle }>
|
||||
{ this._renderErrorList() }
|
||||
<FlexColDiv className="playground-errors-pane" style={errorsPaneStyle}>
|
||||
{this._renderErrorList()}
|
||||
</FlexColDiv>
|
||||
</FlexColDiv>
|
||||
|
||||
<FlexRowDiv className='playground-footer' style={ footerStyle }>
|
||||
<FlexRowDiv className="playground-footer" style={footerStyle}>
|
||||
© 2019 Microsoft
|
||||
</FlexRowDiv>
|
||||
</FlexColDiv>
|
||||
|
@ -172,14 +171,11 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
}
|
||||
}
|
||||
|
||||
DocNodeSyntaxStyler.getStylesForDocComment(
|
||||
syntaxStyles,
|
||||
{
|
||||
docNode: this.state.parserContext.docComment,
|
||||
parserContext: this.state.parserContext,
|
||||
themeName: this.state.selectedTheme
|
||||
}
|
||||
);
|
||||
DocNodeSyntaxStyler.getStylesForDocComment(syntaxStyles, {
|
||||
docNode: this.state.parserContext.docComment,
|
||||
parserContext: this.state.parserContext,
|
||||
themeName: this.state.selectedTheme
|
||||
});
|
||||
}
|
||||
|
||||
const editorStyle: React.CSSProperties = {
|
||||
|
@ -189,21 +185,21 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
};
|
||||
|
||||
return (
|
||||
<FlexColDiv className='playground-input-box' style={ { flex: 1 } }>
|
||||
<div className='playground-button-bar' style={ { height: '40px', boxSizing: 'border-box' } }>
|
||||
{ this._renderSelectSample() }
|
||||
{ this._renderThemeSelector() }
|
||||
<FlexColDiv className="playground-input-box" style={{ flex: 1 }}>
|
||||
<div className="playground-button-bar" style={{ height: '40px', boxSizing: 'border-box' }}>
|
||||
{this._renderSelectSample()}
|
||||
{this._renderThemeSelector()}
|
||||
</div>
|
||||
<CodeEditor
|
||||
className='playground-input-text-editor'
|
||||
style={ editorStyle }
|
||||
value={ this.state.inputText }
|
||||
onChange={ this._inputTextArea_onChange }
|
||||
language='typescript'
|
||||
markers={ markers }
|
||||
syntaxStyles={ syntaxStyles }
|
||||
theme={ this.state.selectedTheme }
|
||||
/>
|
||||
className="playground-input-text-editor"
|
||||
style={editorStyle}
|
||||
value={this.state.inputText}
|
||||
onChange={this._inputTextArea_onChange}
|
||||
language="typescript"
|
||||
markers={markers}
|
||||
syntaxStyles={syntaxStyles}
|
||||
theme={this.state.selectedTheme}
|
||||
/>
|
||||
</FlexColDiv>
|
||||
);
|
||||
}
|
||||
|
@ -211,15 +207,15 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
private _renderSelectSample(): React.ReactNode {
|
||||
return (
|
||||
<select
|
||||
className='playground-select-sample'
|
||||
className="playground-select-sample"
|
||||
value={this.state.selectSampleValue}
|
||||
aria-label='Select a code sample'
|
||||
onChange={this._selectSample_onChange}>
|
||||
|
||||
<option value='none'>Choose a sample...</option>
|
||||
<option value='basic'>A basic example</option>
|
||||
<option value='advanced'>Some advanced features</option>
|
||||
<option value='hyperlink'>Creating hyperlinks</option>
|
||||
aria-label="Select a code sample"
|
||||
onChange={this._selectSample_onChange}
|
||||
>
|
||||
<option value="none">Choose a sample...</option>
|
||||
<option value="basic">A basic example</option>
|
||||
<option value="advanced">Some advanced features</option>
|
||||
<option value="hyperlink">Creating hyperlinks</option>
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
@ -227,13 +223,13 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
private _renderThemeSelector(): React.ReactNode {
|
||||
return (
|
||||
<select
|
||||
className='playground-select-theme'
|
||||
className="playground-select-theme"
|
||||
value={this.state.selectedTheme}
|
||||
aria-label='Select an editor theme'
|
||||
onChange={this._selectTheme_onChange}>
|
||||
|
||||
<option value='vs'>Light Theme</option>
|
||||
<option value='vs-dark'>Dark Theme</option>
|
||||
aria-label="Select an editor theme"
|
||||
onChange={this._selectTheme_onChange}
|
||||
>
|
||||
<option value="vs">Light Theme</option>
|
||||
<option value="vs-dark">Dark Theme</option>
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
@ -266,8 +262,8 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
const parserContext: tsdoc.ParserContext | undefined = this.state.parserContext;
|
||||
if (parserContext && parserContext.docComment) {
|
||||
return (
|
||||
<div style={ { overflow: 'auto', paddingLeft: '8px', paddingRight: '8px', flex: 1 } }>
|
||||
<DocHtmlView docComment={ parserContext.docComment } />
|
||||
<div style={{ overflow: 'auto', paddingLeft: '8px', paddingRight: '8px', flex: 1 }}>
|
||||
<DocHtmlView docComment={parserContext.docComment} />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
@ -276,12 +272,7 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
}
|
||||
|
||||
private _renderDom(): React.ReactNode {
|
||||
return (
|
||||
<DocDomView
|
||||
parserContext={ this.state.parserContext }
|
||||
theme={ this.state.selectedTheme }
|
||||
/>
|
||||
);
|
||||
return <DocDomView parserContext={this.state.parserContext} theme={this.state.selectedTheme} />;
|
||||
}
|
||||
|
||||
private _renderLines(): React.ReactNode {
|
||||
|
@ -293,21 +284,16 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
|
||||
return (
|
||||
<textarea
|
||||
className='playground-lines-text-editor'
|
||||
style={ { ...this._textAreaStyle, border: 'none' } }
|
||||
readOnly={ true }
|
||||
value={ outputText }
|
||||
/>
|
||||
className="playground-lines-text-editor"
|
||||
style={{ ...this._textAreaStyle, border: 'none' }}
|
||||
readOnly={true}
|
||||
value={outputText}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private _renderAst(): React.ReactNode {
|
||||
return (
|
||||
<DocAstView
|
||||
parserContext={this.state.parserContext}
|
||||
theme={ this.state.selectedTheme }
|
||||
/>
|
||||
);
|
||||
return <DocAstView parserContext={this.state.parserContext} theme={this.state.selectedTheme} />;
|
||||
}
|
||||
|
||||
private _renderEmitter(): React.ReactNode {
|
||||
|
@ -319,10 +305,10 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
|
||||
return (
|
||||
<CodeEditor
|
||||
className='playground-emitter-text-editor'
|
||||
readOnly={ true }
|
||||
value={ outputText }
|
||||
theme={ this.state.selectedTheme }
|
||||
className="playground-emitter-text-editor"
|
||||
readOnly={true}
|
||||
value={outputText}
|
||||
theme={this.state.selectedTheme}
|
||||
wordWrap={true}
|
||||
/>
|
||||
);
|
||||
|
@ -333,7 +319,7 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
if (this.state.parserFailureText) {
|
||||
errorsText = this.state.parserFailureText;
|
||||
} else if (this.state.parserContext) {
|
||||
errorsText = this.state.parserContext.log.messages.map(x => x.toString()).join('\n');
|
||||
errorsText = this.state.parserContext.log.messages.map((x) => x.toString()).join('\n');
|
||||
}
|
||||
|
||||
const boxStyle: React.CSSProperties = {
|
||||
|
@ -345,14 +331,14 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
|
||||
return (
|
||||
<>
|
||||
<label htmlFor='errors'>Errors:</label>
|
||||
<label htmlFor="errors">Errors:</label>
|
||||
<FlexColDiv style={boxStyle}>
|
||||
<textarea
|
||||
id='errors'
|
||||
className='playground-errors-textarea'
|
||||
readOnly={ true }
|
||||
value={ errorsText }
|
||||
style={ this._textAreaStyle }
|
||||
id="errors"
|
||||
className="playground-errors-textarea"
|
||||
readOnly={true}
|
||||
value={errorsText}
|
||||
style={this._textAreaStyle}
|
||||
/>
|
||||
</FlexColDiv>
|
||||
</>
|
||||
|
@ -374,10 +360,12 @@ export class PlaygroundView extends React.Component<IPlaygroundViewProps, IPlayg
|
|||
try {
|
||||
const inputText: string = this.state.inputText;
|
||||
const configuration: tsdoc.TSDocConfiguration = new tsdoc.TSDocConfiguration();
|
||||
configuration.addTagDefinition(new tsdoc.TSDocTagDefinition({
|
||||
tagName: '@sampleCustomBlockTag',
|
||||
syntaxKind: tsdoc.TSDocTagSyntaxKind.BlockTag
|
||||
}));
|
||||
configuration.addTagDefinition(
|
||||
new tsdoc.TSDocTagDefinition({
|
||||
tagName: '@sampleCustomBlockTag',
|
||||
syntaxKind: tsdoc.TSDocTagSyntaxKind.BlockTag
|
||||
})
|
||||
);
|
||||
const tsdocParser: tsdoc.TSDocParser = new tsdoc.TSDocParser(configuration);
|
||||
const parserContext: tsdoc.ParserContext = tsdocParser.parseString(inputText);
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import * as tsdoc from '@microsoft/tsdoc';
|
||||
|
||||
import {
|
||||
MonacoTSDocTheme,
|
||||
IDocNodeSyntaxStylerTheme,
|
||||
IThemeRule
|
||||
} from './DocNodeSyntaxStylerTheme';
|
||||
import { MonacoTSDocTheme, IDocNodeSyntaxStylerTheme, IThemeRule } from './DocNodeSyntaxStylerTheme';
|
||||
import { IStyledRange } from './../CodeEditor';
|
||||
|
||||
import './syntaxStyles.css';
|
||||
|
@ -20,7 +16,9 @@ interface IAddTokenStylesOptions {
|
|||
theme: IDocNodeSyntaxStylerTheme;
|
||||
}
|
||||
|
||||
interface IGetStylesForDocCommentInternalOptions extends IGetStylesForDocCommentOptions, IAddTokenStylesOptions {
|
||||
interface IGetStylesForDocCommentInternalOptions
|
||||
extends IGetStylesForDocCommentOptions,
|
||||
IAddTokenStylesOptions {
|
||||
parentNode?: tsdoc.DocNode;
|
||||
}
|
||||
|
||||
|
@ -32,7 +30,10 @@ export class DocNodeSyntaxStyler {
|
|||
private static _classNameId: number = 0;
|
||||
private static _themeCache: { [hash: string]: IThemeClassNameMapping } = {};
|
||||
|
||||
public static getStylesForDocComment(styles: IStyledRange[], options: IGetStylesForDocCommentOptions): void {
|
||||
public static getStylesForDocComment(
|
||||
styles: IStyledRange[],
|
||||
options: IGetStylesForDocCommentOptions
|
||||
): void {
|
||||
let theme: IDocNodeSyntaxStylerTheme;
|
||||
switch (options.themeName) {
|
||||
default:
|
||||
|
@ -47,26 +48,18 @@ export class DocNodeSyntaxStyler {
|
|||
}
|
||||
}
|
||||
|
||||
DocNodeSyntaxStyler._getStylesForDocCommentInternal(
|
||||
styles,
|
||||
{
|
||||
...options,
|
||||
theme,
|
||||
styleTokens: ['tsdoc']
|
||||
}
|
||||
);
|
||||
DocNodeSyntaxStyler._getStylesForDocCommentInternal(styles, {
|
||||
...options,
|
||||
theme,
|
||||
styleTokens: ['tsdoc']
|
||||
});
|
||||
}
|
||||
|
||||
public static _getStylesForDocCommentInternal(
|
||||
styles: IStyledRange[],
|
||||
options: IGetStylesForDocCommentInternalOptions
|
||||
): void {
|
||||
const {
|
||||
docNode,
|
||||
parserContext,
|
||||
styleTokens,
|
||||
theme
|
||||
}: IGetStylesForDocCommentInternalOptions = options;
|
||||
const { docNode, parserContext, styleTokens, theme }: IGetStylesForDocCommentInternalOptions = options;
|
||||
|
||||
if (docNode instanceof tsdoc.DocExcerpt) {
|
||||
// Match the context against a color (i.e. tsdoc.link.url)
|
||||
|
@ -94,149 +87,131 @@ export class DocNodeSyntaxStyler {
|
|||
case 'MemberReference_LeftParenthesis':
|
||||
case 'MemberReference_RightParenthesis':
|
||||
case 'ParamBlock_Hyphen': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'delimiter'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'delimiter']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'InlineTag_TagName':
|
||||
case 'BlockTag': {
|
||||
const tagDefinition: tsdoc.TSDocTagDefinition | undefined = parserContext.configuration.tryGetTagDefinition(
|
||||
docNode.content.toString()
|
||||
);
|
||||
DocNodeSyntaxStyler._addStylesForTag(
|
||||
styles,
|
||||
docNode.content,
|
||||
tagDefinition,
|
||||
{ theme, styleTokens: [...styleTokens, 'tag'] }
|
||||
);
|
||||
const tagDefinition:
|
||||
| tsdoc.TSDocTagDefinition
|
||||
| undefined = parserContext.configuration.tryGetTagDefinition(docNode.content.toString());
|
||||
DocNodeSyntaxStyler._addStylesForTag(styles, docNode.content, tagDefinition, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'tag']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'MemberIdentifier_Identifier': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'member', 'identifier'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'member', 'identifier']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'DeclarationReference_PackageName': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'packageName'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'packageName']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'DeclarationReference_ImportPath': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'importPath'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'importPath']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'LinkTag_UrlDestination': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'url'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'url']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'CodeSpan_Code':
|
||||
case 'FencedCode_Code': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'code'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'code']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'FencedCode_Language': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'language'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'language']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'HtmlEndTag_Name':
|
||||
case 'HtmlStartTag_Name': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'element', 'name'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'element', 'name']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'HtmlAttribute_Name': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'element', 'attribute', 'name'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'element', 'attribute', 'name']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'HtmlAttribute_Value': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'element', 'attribute', 'value'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'element', 'attribute', 'value']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'ErrorText': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'error'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'error']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'EscapedText': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'escaped'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'escaped']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'MemberSelector': {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
docNode.content,
|
||||
{ theme, styleTokens: [...styleTokens, 'member', 'selector'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, docNode.content, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'member', 'selector']
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const child of docNode.getChildNodes()) {
|
||||
DocNodeSyntaxStyler._getStylesForDocCommentInternal(
|
||||
styles,
|
||||
{
|
||||
...options,
|
||||
parentNode: docNode,
|
||||
docNode: child
|
||||
}
|
||||
);
|
||||
DocNodeSyntaxStyler._getStylesForDocCommentInternal(styles, {
|
||||
...options,
|
||||
parentNode: docNode,
|
||||
docNode: child
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,46 +221,39 @@ export class DocNodeSyntaxStyler {
|
|||
tagDefinition: tsdoc.TSDocTagDefinition | undefined,
|
||||
options: IAddTokenStylesOptions
|
||||
): void {
|
||||
const {
|
||||
theme,
|
||||
styleTokens
|
||||
}: IAddTokenStylesOptions = options;
|
||||
const { theme, styleTokens }: IAddTokenStylesOptions = options;
|
||||
if (tagDefinition) {
|
||||
switch (tagDefinition.syntaxKind) {
|
||||
case tsdoc.TSDocTagSyntaxKind.BlockTag: {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
excerpt,
|
||||
{ theme, styleTokens: [...styleTokens, 'block'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, excerpt, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'block']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case tsdoc.TSDocTagSyntaxKind.InlineTag: {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
excerpt,
|
||||
{ theme, styleTokens: [...styleTokens, 'inline'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, excerpt, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'inline']
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case tsdoc.TSDocTagSyntaxKind.ModifierTag: {
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
excerpt,
|
||||
{ theme, styleTokens: [...styleTokens, 'modifier'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, excerpt, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'modifier']
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Undefined tag
|
||||
DocNodeSyntaxStyler._addTokenStyles(
|
||||
styles,
|
||||
excerpt,
|
||||
{ theme, styleTokens: [...styleTokens, 'undefined'] }
|
||||
);
|
||||
DocNodeSyntaxStyler._addTokenStyles(styles, excerpt, {
|
||||
theme,
|
||||
styleTokens: [...styleTokens, 'undefined']
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
margin-left: -1px;
|
||||
}
|
||||
|
||||
.tsdoc-blocktag+.tsdoc-blocktag {
|
||||
.tsdoc-blocktag + .tsdoc-blocktag {
|
||||
border-left-style: none;
|
||||
border-top-left-radius: 0px;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export interface ITabPaneState {
|
|||
selectedTabIndex: number;
|
||||
}
|
||||
|
||||
export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
||||
export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
||||
// Saved bindings of _onClickTab() with a tabIndex parameter, to avoid the react/jsx-no-bind issue
|
||||
private _onClickTabBindings: React.MouseEventHandler<HTMLAnchorElement>[] = [];
|
||||
|
||||
|
@ -36,7 +36,7 @@ export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
|||
let selectedTabDefinition: ITabDefinition | undefined = undefined;
|
||||
|
||||
for (let i: number = 0; i < this.props.tabs.length; ++i) {
|
||||
const tabDefinition: ITabDefinition = this.props.tabs[i];
|
||||
const tabDefinition: ITabDefinition = this.props.tabs[i];
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
padding: '8px',
|
||||
|
@ -58,28 +58,27 @@ export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
|||
};
|
||||
|
||||
buttons.push(
|
||||
<div key={`tab_${i}`} className='playground-tab-pane-active-tab' style={ activeTabStyle }>
|
||||
<div key={`tab_${i}`} className="playground-tab-pane-active-tab" style={activeTabStyle}>
|
||||
{tabDefinition.title}
|
||||
</div>
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
if (!this._onClickTabBindings[i]) {
|
||||
// Bind _onClickTab() with i as the tabIndex parameter
|
||||
this._onClickTabBindings[i] = this._onClickTab.bind(this, i);
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
<div key={`tab_${i}`} className='playground-tab-pane-inactive-tab' style={ style }>
|
||||
<a href='#'
|
||||
style={ { textDecorationLine: 'none', color: '#000000' } }
|
||||
onClick={ this._onClickTabBindings[i] }>
|
||||
<div key={`tab_${i}`} className="playground-tab-pane-inactive-tab" style={style}>
|
||||
<a
|
||||
href="#"
|
||||
style={{ textDecorationLine: 'none', color: '#000000' }}
|
||||
onClick={this._onClickTabBindings[i]}
|
||||
>
|
||||
{tabDefinition.title}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,12 +96,12 @@ export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
|||
};
|
||||
|
||||
return (
|
||||
<FlexColDiv className='playground-tab-pane' style={ tabPaneStyle }>
|
||||
<FlexRowDiv className='playground-tab-pane-buttons' style={ this.props.buttonRowStyle }>
|
||||
{ buttons }
|
||||
<FlexColDiv className="playground-tab-pane" style={tabPaneStyle}>
|
||||
<FlexRowDiv className="playground-tab-pane-buttons" style={this.props.buttonRowStyle}>
|
||||
{buttons}
|
||||
</FlexRowDiv>
|
||||
<FlexColDiv className='playground-tab-pane-content' style={ contentDivStyle }>
|
||||
{ selectedTabDefinition !== undefined ? selectedTabDefinition.render() : '' }
|
||||
<FlexColDiv className="playground-tab-pane-content" style={contentDivStyle}>
|
||||
{selectedTabDefinition !== undefined ? selectedTabDefinition.render() : ''}
|
||||
</FlexColDiv>
|
||||
</FlexColDiv>
|
||||
);
|
||||
|
@ -111,5 +110,4 @@ export class TabPane extends React.Component<ITabPaneProps, ITabPaneState> {
|
|||
private _onClickTab(tabIndex: number, event: React.MouseEvent<HTMLAnchorElement>): void {
|
||||
this.setState({ selectedTabIndex: tabIndex });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
html, body {
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: Tahoma, sans-serif;
|
||||
}
|
||||
|
||||
.doc-heading {
|
||||
color: #2F5496;
|
||||
color: #2f5496;
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
@ -14,10 +15,11 @@ html, body {
|
|||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.doc-table th, td {
|
||||
.doc-table th,
|
||||
td {
|
||||
text-align: left;
|
||||
padding: 5px 10px;
|
||||
border-bottom: 2px solid #e0e0e0
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.doc-fenced-code {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
export namespace SampleInputs {
|
||||
export const advanced: string = require('raw-loader!./advancedSample.ts');
|
||||
export const basic: string = require('raw-loader!./basicSample.ts');
|
||||
|
|
|
@ -13,9 +13,9 @@ if (!webpackConfiguration.devServer.headers) {
|
|||
}
|
||||
|
||||
webpackConfiguration.devServer.headers = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
...webpackConfiguration.devServer.headers
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = webpackConfiguration;
|
||||
|
|
|
@ -16,16 +16,17 @@ const REACT_DOM_URL = {
|
|||
};
|
||||
const REACT_DOM_SERVER_URL = {
|
||||
dev: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.1/umd/react-dom-server.browser.development.js',
|
||||
production: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.1/umd/react-dom-server.browser.production.min.js'
|
||||
production:
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.1/umd/react-dom-server.browser.production.min.js'
|
||||
};
|
||||
const MONACO_URL = {
|
||||
dev: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.14.3/min/',
|
||||
production: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.14.3/min/'
|
||||
};
|
||||
|
||||
module.exports.generateBuildWebpackConfiguration = function(env) {
|
||||
return _generateBaseWebpackConfiguration((env || {}).production);
|
||||
}
|
||||
module.exports.generateBuildWebpackConfiguration = function (env) {
|
||||
return _generateBaseWebpackConfiguration((env || {}).production);
|
||||
};
|
||||
|
||||
module.exports.generateServeWebpackConfiguration = function () {
|
||||
const result = _generateBaseWebpackConfiguration(false);
|
||||
|
@ -37,7 +38,7 @@ module.exports.generateServeWebpackConfiguration = function () {
|
|||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function _generateBaseWebpackConfiguration(isProduction) {
|
||||
const distDirectory = path.join(__dirname, 'dist');
|
||||
|
@ -49,10 +50,7 @@ function _generateBaseWebpackConfiguration(isProduction) {
|
|||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
require.resolve('style-loader'),
|
||||
require.resolve('css-loader')
|
||||
]
|
||||
use: [require.resolve('style-loader'), require.resolve('css-loader')]
|
||||
},
|
||||
{
|
||||
test: /\.(scss|sass)$/,
|
||||
|
@ -74,15 +72,15 @@ function _generateBaseWebpackConfiguration(isProduction) {
|
|||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json'],
|
||||
alias: {
|
||||
'tslib': 'tslib/tslib.es6'
|
||||
tslib: 'tslib/tslib.es6'
|
||||
}
|
||||
},
|
||||
devtool: (isProduction) ? undefined : 'source-map',
|
||||
devtool: isProduction ? undefined : 'source-map',
|
||||
entry: {
|
||||
'tsdoc-playground': path.join(__dirname, 'lib', 'index.js')
|
||||
},
|
||||
externals: {
|
||||
'react': 'React',
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-dom/server': 'ReactDOMServer'
|
||||
},
|
||||
|
@ -112,7 +110,7 @@ function _generateBaseWebpackConfiguration(isProduction) {
|
|||
new SetPublicPathPlugin({
|
||||
scriptName: {
|
||||
isTokenized: true,
|
||||
name: '[name]_?[a-zA-Z0-9-_]*\.js'
|
||||
name: '[name]_?[a-zA-Z0-9-_]*.js'
|
||||
}
|
||||
}),
|
||||
new BundleAnalyzerPlugin({
|
||||
|
|
20
rush.json
20
rush.json
|
@ -215,7 +215,7 @@
|
|||
// "tools", // non-shipping projects that are part of the developer toolchain
|
||||
// "prototypes" // experiments that should mostly be ignored by the review process
|
||||
// ],
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * A list of NPM package scopes that will be excluded from review.
|
||||
// * We recommend to exclude TypeScript typings (the "@types" scope), because
|
||||
|
@ -341,7 +341,7 @@
|
|||
// * The folder name for this variant.
|
||||
// */
|
||||
// "variantName": "old-sdk",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * An informative description
|
||||
// */
|
||||
|
@ -380,19 +380,19 @@
|
|||
// * The NPM package name of the project (must match package.json)
|
||||
// */
|
||||
// "packageName": "my-app",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * The path to the project folder, relative to the rush.json config file.
|
||||
// */
|
||||
// "projectFolder": "apps/my-app",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * An optional category for usage in the "browser-approved-packages.json"
|
||||
// * and "nonbrowser-approved-packages.json" files. The value must be one of the
|
||||
// * strings from the "reviewCategories" defined above.
|
||||
// */
|
||||
// "reviewCategory": "production",
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * A list of local projects that appear as devDependencies for this project, but cannot be
|
||||
// * locally linked because it would create a cyclic dependency; instead, the last published
|
||||
|
@ -401,20 +401,20 @@
|
|||
// "cyclicDependencyProjects": [
|
||||
// // "my-toolchain"
|
||||
// ],
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * If true, then this project will be ignored by the "rush check" command.
|
||||
// * The default value is false.
|
||||
// */
|
||||
// // "skipRushCheck": false,
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * A flag indicating that changes to this project will be published to npm, which affects
|
||||
// * the Rush change and publish workflows. The default value is false.
|
||||
// * NOTE: "versionPolicyName" and "shouldPublish" are alternatives; you cannot specify them both.
|
||||
// */
|
||||
// // "shouldPublish": false,
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * An optional version policy associated with the project. Version policies are defined
|
||||
// * in "version-policies.json" file. See the "rush publish" documentation for more info.
|
||||
|
@ -422,13 +422,13 @@
|
|||
// */
|
||||
// // "versionPolicyName": ""
|
||||
// },
|
||||
//
|
||||
//
|
||||
// {
|
||||
// "packageName": "my-controls",
|
||||
// "projectFolder": "libraries/my-controls",
|
||||
// "reviewCategory": "production"
|
||||
// },
|
||||
//
|
||||
//
|
||||
// {
|
||||
// "packageName": "my-toolchain",
|
||||
// "projectFolder": "tools/my-toolchain",
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
// - Label selectors refer to declarations indicated using the {@label LABEL} tag. The label
|
||||
// must be all capitals (e.g. "WITH_NUMBERS") to avoid conflicts with system selectors.
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Static vs instance members
|
||||
|
||||
|
@ -72,8 +71,7 @@ export class ClassA1 {
|
|||
* Shortest name: {@link ClassA1.memberA2}
|
||||
* Full name: {@link (ClassA1:class).(memberA2:instance)}
|
||||
*/
|
||||
public memberA2(): void {
|
||||
}
|
||||
public memberA2(): void {}
|
||||
|
||||
/**
|
||||
* Shortest name: {@link ClassA1.(memberA3:instance)}
|
||||
|
@ -82,15 +80,13 @@ export class ClassA1 {
|
|||
* NOTE: The shortest name cannot omit "instance" because there is a static member
|
||||
* with the same name.
|
||||
*/
|
||||
public memberA3(): void {
|
||||
}
|
||||
public memberA3(): void {}
|
||||
|
||||
/**
|
||||
* Shortest name: {@link ClassA1.(memberA3:static)}
|
||||
* Full name: {@link (ClassA1:class).(memberA3:static)}
|
||||
*/
|
||||
public static memberA3(): void {
|
||||
}
|
||||
public static memberA3(): void {}
|
||||
|
||||
/**
|
||||
* Shortest name: {@link (ClassA1:constructor)}
|
||||
|
@ -128,8 +124,7 @@ export namespace B1.B2.B3 {
|
|||
* Shortest name: {@link B1.B2.B3.functionB4}
|
||||
* Full name: {@link (B1:namespace).(B2:namespace).(B3:namespace).(functionB4:function)}
|
||||
*/
|
||||
export function functionB4(): void {
|
||||
}
|
||||
export function functionB4(): void {}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -196,7 +191,6 @@ export function functionD1(xy?: string | number): string | number {
|
|||
* Full name: {@link (MergedE1:class)}
|
||||
*/
|
||||
export class MergedE1 {
|
||||
|
||||
/**
|
||||
* Shortest name: {@link (MergedE1:constructor)}
|
||||
* Full name: {@link (MergedE1:constructor)}
|
||||
|
@ -223,8 +217,7 @@ export class MergedE1 {
|
|||
* the TSDoc standard discourages that, because resolving it might require
|
||||
* unbounded backtracking.
|
||||
*/
|
||||
public memberE2(): void {
|
||||
}
|
||||
public memberE2(): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,8 +229,7 @@ export namespace MergedE1 {
|
|||
* Shortest name: {@link (MergedE1:namespace).memberE2}
|
||||
* Full name: {@link (MergedE1:namespace).(memberE2:function)}
|
||||
*/
|
||||
export function memberE2(): void {
|
||||
}
|
||||
export function memberE2(): void {}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
@ -266,8 +258,7 @@ export function MergedF1(xy: string | number): string | number {
|
|||
* Shortest name: {@link (MergedF1:namespace)}
|
||||
* Full name: {@link (MergedF1:namespace)}
|
||||
*/
|
||||
export namespace MergedF1 {
|
||||
}
|
||||
export namespace MergedF1 {}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Merged declarations with extension of the same thing
|
||||
|
@ -320,7 +311,6 @@ export namespace MergedG1 {
|
|||
export let mergedG3: string = '';
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Enum members
|
||||
|
||||
|
@ -371,7 +361,6 @@ export class ClassI1 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Malformed names
|
||||
//
|
||||
|
@ -420,7 +409,6 @@ export interface InterfaceJ1 {
|
|||
*/
|
||||
'©': string;
|
||||
|
||||
|
||||
/**
|
||||
* Shortest name: {@link InterfaceJ1."1.5"}
|
||||
* Full name: {@link (InterfaceJ1:interface)."1.5"}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
||||
require("@rushstack/eslint-config/patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
"@rushstack/eslint-config/profile/node",
|
||||
"@rushstack/eslint-config/mixins/friendly-locals",
|
||||
],
|
||||
extends: ['@rushstack/eslint-config/profile/node', '@rushstack/eslint-config/mixins/friendly-locals'],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
TSDocMessageId,
|
||||
ParserMessage,
|
||||
TextRange,
|
||||
IParserMessageParameters
|
||||
IParserMessageParameters,
|
||||
} from '@microsoft/tsdoc';
|
||||
import * as fs from 'fs';
|
||||
import * as resolve from 'resolve';
|
||||
|
@ -48,8 +48,8 @@ interface IConfigJson {
|
|||
*/
|
||||
export class TSDocConfigFile {
|
||||
public static readonly FILENAME: string = 'tsdoc.json';
|
||||
public static readonly CURRENT_SCHEMA_URL: string
|
||||
= 'https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json';
|
||||
public static readonly CURRENT_SCHEMA_URL: string =
|
||||
'https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json';
|
||||
|
||||
/**
|
||||
* A queryable log that reports warnings and error messages that occurred during parsing.
|
||||
|
@ -75,7 +75,7 @@ export class TSDocConfigFile {
|
|||
this._fileMTime = 0;
|
||||
this._tsdocSchema = '';
|
||||
this._extendsPaths = [];
|
||||
this._tagDefinitions= [];
|
||||
this._tagDefinitions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,7 +191,7 @@ export class TSDocConfigFile {
|
|||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileUnsupportedSchema,
|
||||
messageText: `Unsupported JSON "$schema" value; expecting "${TSDocConfigFile.CURRENT_SCHEMA_URL}"`,
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ export class TSDocConfigFile {
|
|||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileSchemaError,
|
||||
messageText: 'Error loading config file: ' + description,
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -217,29 +217,39 @@ export class TSDocConfigFile {
|
|||
for (const jsonTagDefinition of configJson.tagDefinitions || []) {
|
||||
let syntaxKind: TSDocTagSyntaxKind;
|
||||
switch (jsonTagDefinition.syntaxKind) {
|
||||
case 'inline': syntaxKind = TSDocTagSyntaxKind.InlineTag; break;
|
||||
case 'block': syntaxKind = TSDocTagSyntaxKind.BlockTag; break;
|
||||
case 'modifier': syntaxKind = TSDocTagSyntaxKind.ModifierTag; break;
|
||||
case 'inline':
|
||||
syntaxKind = TSDocTagSyntaxKind.InlineTag;
|
||||
break;
|
||||
case 'block':
|
||||
syntaxKind = TSDocTagSyntaxKind.BlockTag;
|
||||
break;
|
||||
case 'modifier':
|
||||
syntaxKind = TSDocTagSyntaxKind.ModifierTag;
|
||||
break;
|
||||
default:
|
||||
// The JSON schema should have caught this error
|
||||
throw new Error('Unexpected tag kind');
|
||||
}
|
||||
this._tagDefinitions.push(new TSDocTagDefinition({
|
||||
tagName: jsonTagDefinition.tagName,
|
||||
syntaxKind: syntaxKind,
|
||||
allowMultiple: jsonTagDefinition.allowMultiple
|
||||
}));
|
||||
this._tagDefinitions.push(
|
||||
new TSDocTagDefinition({
|
||||
tagName: jsonTagDefinition.tagName,
|
||||
syntaxKind: syntaxKind,
|
||||
allowMultiple: jsonTagDefinition.allowMultiple,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _loadWithExtends(configFilePath: string, referencingConfigFile: TSDocConfigFile | undefined,
|
||||
alreadyVisitedPaths: Set<string>): void {
|
||||
|
||||
private _loadWithExtends(
|
||||
configFilePath: string,
|
||||
referencingConfigFile: TSDocConfigFile | undefined,
|
||||
alreadyVisitedPaths: Set<string>
|
||||
): void {
|
||||
if (!configFilePath) {
|
||||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileNotFound,
|
||||
messageText: 'File not found',
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -250,7 +260,7 @@ export class TSDocConfigFile {
|
|||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileNotFound,
|
||||
messageText: 'File not found',
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -260,7 +270,7 @@ export class TSDocConfigFile {
|
|||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileCyclicExtends,
|
||||
messageText: `Circular reference encountered for "extends" field of "${referencingConfigFile.filePath}"`,
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -281,7 +291,7 @@ export class TSDocConfigFile {
|
|||
this._reportError({
|
||||
messageId: TSDocMessageId.ConfigFileUnresolvedExtends,
|
||||
messageText: `Unable to resolve "extends" reference to "${extendsField}"`,
|
||||
textRange: TextRange.empty
|
||||
textRange: TextRange.empty,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,7 @@ import * as path from 'path';
|
|||
import { TSDocConfigFile } from '../TSDocConfigFile';
|
||||
|
||||
function getRelativePath(testPath: string): string {
|
||||
return path
|
||||
.relative(__dirname, testPath)
|
||||
.split('\\')
|
||||
.join('/');
|
||||
return path.relative(__dirname, testPath).split('\\').join('/');
|
||||
}
|
||||
|
||||
expect.addSnapshotSerializer({
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
{
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
{
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
{
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
||||
"extends": [
|
||||
"./base1/tsdoc-base1.json",
|
||||
"./base2/tsdoc-base2.json"
|
||||
],
|
||||
"extends": ["./base1/tsdoc-base1.json", "./base2/tsdoc-base2.json"],
|
||||
"tagDefinitions": [
|
||||
{
|
||||
"tagName": "@root",
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
{
|
||||
}
|
||||
{}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
|
||||
"extends": [
|
||||
"example-lib/dist/tsdoc-example.json"
|
||||
],
|
||||
"extends": ["example-lib/dist/tsdoc-example.json"],
|
||||
"tagDefinitions": [
|
||||
{
|
||||
"tagName": "@root",
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
// This is a workaround for https://github.com/eslint/eslint/issues/3458
|
||||
require("@rushstack/eslint-config/patch/modern-module-resolution");
|
||||
require('@rushstack/eslint-config/patch/modern-module-resolution');
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
"@rushstack/eslint-config/profile/web-app",
|
||||
"@rushstack/eslint-config/mixins/friendly-locals",
|
||||
],
|
||||
parserOptions: { tsconfigRootDir: __dirname },
|
||||
extends: ['@rushstack/eslint-config/profile/web-app', '@rushstack/eslint-config/mixins/friendly-locals'],
|
||||
parserOptions: { tsconfigRootDir: __dirname }
|
||||
};
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"required": [ "$schema" ],
|
||||
"required": ["$schema"],
|
||||
"additionalProperties": false,
|
||||
|
||||
"definitions": {
|
||||
|
|
|
@ -20,7 +20,5 @@ test('01 trimSpacesInParagraphNodes()', () => {
|
|||
expect(firstNode.kind).toEqual(DocNodeKind.Paragraph);
|
||||
const paragraph: DocParagraph = firstNode as DocParagraph;
|
||||
const transformedParagraph: DocParagraph = DocNodeTransforms.trimSpacesInParagraph(paragraph);
|
||||
expect(
|
||||
TestHelpers.getDocNodeSnapshot(transformedParagraph)
|
||||
).toMatchSnapshot();
|
||||
expect(TestHelpers.getDocNodeSnapshot(transformedParagraph)).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -4,69 +4,57 @@ import { DocSection, DocPlainText, DocSoftBreak, DocParagraph, DocBlockTag } fro
|
|||
import { TSDocConfiguration } from '../configuration/TSDocConfiguration';
|
||||
|
||||
test('01 Basic paragraph splitting', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * ',
|
||||
' * This is the',
|
||||
' * first paragraph.',
|
||||
' * \t ',
|
||||
' * ',
|
||||
' * \t ',
|
||||
' * This is the second paragraph.',
|
||||
' *',
|
||||
' * This is the third paragraph.',
|
||||
' *',
|
||||
' * ',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * ',
|
||||
' * This is the',
|
||||
' * first paragraph.',
|
||||
' * \t ',
|
||||
' * ',
|
||||
' * \t ',
|
||||
' * This is the second paragraph.',
|
||||
' *',
|
||||
' * This is the third paragraph.',
|
||||
' *',
|
||||
' * ',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('02 Basic paragraph splitting in blocks', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * P1',
|
||||
' * @remarks P2',
|
||||
' *',
|
||||
' * P3 @deprecated P4',
|
||||
' *',
|
||||
' * P5',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
['/**', ' * P1', ' * @remarks P2', ' *', ' * P3 @deprecated P4', ' *', ' * P5', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('03 Degenerate comment framing', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/** line 1',
|
||||
' * line 2',
|
||||
'',
|
||||
' * @public line 3*/'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
['/** line 1', ' * line 2', '', ' * @public line 3*/'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 Degenerate manually constructed nodes', () => {
|
||||
const configuration: TSDocConfiguration = new TSDocConfiguration();
|
||||
|
||||
const docSection: DocSection = new DocSection({ configuration },
|
||||
[
|
||||
new DocParagraph({ configuration },
|
||||
[
|
||||
new DocPlainText({ configuration, text: ' para 1 ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' \t ' }),
|
||||
new DocPlainText({ configuration, text: ' ' }),
|
||||
new DocBlockTag( { configuration, tagName: '@public' }),
|
||||
new DocPlainText({ configuration, text: ' para 2 ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' para 3 ' })
|
||||
]
|
||||
),
|
||||
// Currently we do not discard empty paragraphs
|
||||
new DocParagraph({ configuration })
|
||||
]
|
||||
);
|
||||
const docSection: DocSection = new DocSection({ configuration }, [
|
||||
new DocParagraph({ configuration }, [
|
||||
new DocPlainText({ configuration, text: ' para 1 ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' \t ' }),
|
||||
new DocPlainText({ configuration, text: ' ' }),
|
||||
new DocBlockTag({ configuration, tagName: '@public' }),
|
||||
new DocPlainText({ configuration, text: ' para 2 ' }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocSoftBreak({ configuration }),
|
||||
new DocPlainText({ configuration, text: ' para 3 ' })
|
||||
]),
|
||||
// Currently we do not discard empty paragraphs
|
||||
new DocParagraph({ configuration })
|
||||
]);
|
||||
|
||||
ParagraphSplitter.splitParagraphsForSection(docSection);
|
||||
expect(TestHelpers.getDocNodeSnapshot(docSection)).toMatchSnapshot();
|
||||
|
|
|
@ -9,13 +9,9 @@ import {
|
|||
import { TestHelpers } from '../parser/__tests__/TestHelpers';
|
||||
|
||||
test('01 Simple @beta and @internal extraction', () => {
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * START @beta',
|
||||
' * @unknownTag',
|
||||
' * @internal @internal END',
|
||||
' */'
|
||||
].join('\n'));
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
['/**', ' * START @beta', ' * @unknownTag', ' * @internal @internal END', ' */'].join('\n')
|
||||
);
|
||||
|
||||
const docComment: DocComment = parserContext.docComment;
|
||||
const modifierTagSet: StandardModifierTagSet = docComment.modifierTagSet;
|
||||
|
@ -38,23 +34,26 @@ test('02 A basic TSDoc comment with common components', () => {
|
|||
})
|
||||
]);
|
||||
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * Returns the average of two numbers.',
|
||||
' *',
|
||||
' * @remarks',
|
||||
' * This method is part of the {@link core-library#Statistics | Statistics subsystem}.',
|
||||
' *',
|
||||
' * @customBlock',
|
||||
' * This is a custom block containing an @undefinedBlockTag',
|
||||
' *',
|
||||
' * @param x - The first input number',
|
||||
' * @param y$_ - The second input number',
|
||||
' * @returns The arithmetic mean of `x` and `y$_`',
|
||||
' *',
|
||||
' * @beta @customModifier',
|
||||
' */'
|
||||
].join('\n'), configuration);
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * Returns the average of two numbers.',
|
||||
' *',
|
||||
' * @remarks',
|
||||
' * This method is part of the {@link core-library#Statistics | Statistics subsystem}.',
|
||||
' *',
|
||||
' * @customBlock',
|
||||
' * This is a custom block containing an @undefinedBlockTag',
|
||||
' *',
|
||||
' * @param x - The first input number',
|
||||
' * @param y$_ - The second input number',
|
||||
' * @returns The arithmetic mean of `x` and `y$_`',
|
||||
' *',
|
||||
' * @beta @customModifier',
|
||||
' */'
|
||||
].join('\n'),
|
||||
configuration
|
||||
);
|
||||
|
||||
const docComment: DocComment = parserContext.docComment;
|
||||
expect(docComment.modifierTagSet.hasTagName('@customModifier')).toEqual(true);
|
||||
|
@ -73,88 +72,93 @@ test('03 Jumbled order', () => {
|
|||
})
|
||||
]);
|
||||
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * Returns the average of two numbers. @remarks This method is part of the',
|
||||
' * {@link core-library#Statistics | Statistics subsystem}.',
|
||||
' * @beta @customModifier',
|
||||
' * @returns The arithmetic mean of `x` and `y`',
|
||||
' * @param x - The first input number @param y - The second input number',
|
||||
' * @customBlock',
|
||||
' * This is a custom block containing an @undefinedBlockTag',
|
||||
' */'
|
||||
].join('\n'), configuration);
|
||||
const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * Returns the average of two numbers. @remarks This method is part of the',
|
||||
' * {@link core-library#Statistics | Statistics subsystem}.',
|
||||
' * @beta @customModifier',
|
||||
' * @returns The arithmetic mean of `x` and `y`',
|
||||
' * @param x - The first input number @param y - The second input number',
|
||||
' * @customBlock',
|
||||
' * This is a custom block containing an @undefinedBlockTag',
|
||||
' */'
|
||||
].join('\n'),
|
||||
configuration
|
||||
);
|
||||
|
||||
const docComment: DocComment = parserContext.docComment;
|
||||
expect(docComment.modifierTagSet.hasTagName('@customModifier')).toEqual(true);
|
||||
});
|
||||
|
||||
test('03 Incomplete @param blocks', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * @param - The first input number',
|
||||
' * @param y The second input number',
|
||||
' * @returns The arithmetic mean of `x` and `y`',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * @param - The first input number',
|
||||
' * @param y The second input number',
|
||||
' * @returns The arithmetic mean of `x` and `y`',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 typeParam blocks', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * Constructs a map from a JavaScript object',
|
||||
' *',
|
||||
' * @typeParam K - The generic type parameter indicating the key type',
|
||||
' * @param jsonObject - The input object',
|
||||
' * @typeParam V - The generic type parameter indicating the value type',
|
||||
' * @returns The map',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * Constructs a map from a JavaScript object',
|
||||
' *',
|
||||
' * @typeParam K - The generic type parameter indicating the key type',
|
||||
' * @param jsonObject - The input object',
|
||||
' * @typeParam V - The generic type parameter indicating the value type',
|
||||
' * @returns The map',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('05 Invalid JSDoc syntax in @param blocks', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * @param {type} a - description',
|
||||
' * @param {{}} b - description',
|
||||
' * @param {"{"} c - description',
|
||||
' * @param {"\\""} d - description',
|
||||
' * @param e {type} - description',
|
||||
' * @param f {{}} - description',
|
||||
' * @param g {"{"} - description',
|
||||
' * @param h - {type} description',
|
||||
' * @param i - {{}} description',
|
||||
' * @param j - {"{"} description',
|
||||
' * @param [k] - description',
|
||||
' * @param [l=] - description',
|
||||
' * @param [m=[]] - description',
|
||||
' * @param [n="["] - description',
|
||||
' * @param [o="\\""] - description',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * @param {type} a - description',
|
||||
' * @param {{}} b - description',
|
||||
' * @param {"{"} c - description',
|
||||
' * @param {"\\""} d - description',
|
||||
' * @param e {type} - description',
|
||||
' * @param f {{}} - description',
|
||||
' * @param g {"{"} - description',
|
||||
' * @param h - {type} description',
|
||||
' * @param i - {{}} description',
|
||||
' * @param j - {"{"} description',
|
||||
' * @param [k] - description',
|
||||
' * @param [l=] - description',
|
||||
' * @param [m=[]] - description',
|
||||
' * @param [n="["] - description',
|
||||
' * @param [o="\\""] - description',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('06 Invalid JSDoc optional name', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * Example 1',
|
||||
' *',
|
||||
' * @param [n - this is',
|
||||
' * the description',
|
||||
' *',
|
||||
' * @public',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * Example 1',
|
||||
' *',
|
||||
' * @param [n - this is',
|
||||
' * the description',
|
||||
' *',
|
||||
' * @public',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('07 Invalid JSDoc type', () => {
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot([
|
||||
'/**',
|
||||
' * Example 1',
|
||||
' *',
|
||||
' * @param { test',
|
||||
' *',
|
||||
' * @public',
|
||||
' */'
|
||||
].join('\n'));
|
||||
});
|
||||
TestHelpers.parseAndMatchDocCommentSnapshot(
|
||||
['/**', ' * Example 1', ' *', ' * @param { test', ' *', ' * @public', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -19,8 +19,11 @@ export class DeclarationReference {
|
|||
private _navigation: Navigation.Locals | Navigation.Exports | undefined;
|
||||
private _symbol: SymbolReference | undefined;
|
||||
|
||||
public constructor(source?: ModuleSource | GlobalSource, navigation?: Navigation.Locals | Navigation.Exports,
|
||||
symbol?: SymbolReference) {
|
||||
public constructor(
|
||||
source?: ModuleSource | GlobalSource,
|
||||
navigation?: Navigation.Locals | Navigation.Exports,
|
||||
symbol?: SymbolReference
|
||||
) {
|
||||
this._source = source;
|
||||
this._navigation = navigation;
|
||||
this._symbol = symbol;
|
||||
|
@ -48,8 +51,7 @@ export class DeclarationReference {
|
|||
}
|
||||
|
||||
public get isEmpty(): boolean {
|
||||
return this.source === undefined
|
||||
&& this.symbol === undefined;
|
||||
return this.source === undefined && this.symbol === undefined;
|
||||
}
|
||||
|
||||
public static parse(text: string): DeclarationReference {
|
||||
|
@ -77,9 +79,11 @@ export class DeclarationReference {
|
|||
*/
|
||||
public static isWellFormedComponentString(text: string): boolean {
|
||||
const scanner: Scanner = new Scanner(text);
|
||||
return scanner.scan() === Token.String ? scanner.scan() === Token.EofToken :
|
||||
scanner.token() === Token.Text ? scanner.scan() === Token.EofToken :
|
||||
scanner.token() === Token.EofToken;
|
||||
return scanner.scan() === Token.String
|
||||
? scanner.scan() === Token.EofToken
|
||||
: scanner.token() === Token.Text
|
||||
? scanner.scan() === Token.EofToken
|
||||
: scanner.token() === Token.EofToken;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,10 +124,12 @@ export class DeclarationReference {
|
|||
*/
|
||||
public static isWellFormedModuleSourceString(text: string): boolean {
|
||||
const scanner: Scanner = new Scanner(text + '!');
|
||||
return scanner.rescanModuleSource() === Token.ModuleSource
|
||||
&& !scanner.stringIsUnterminated
|
||||
&& scanner.scan() === Token.ExclamationToken
|
||||
&& scanner.scan() === Token.EofToken;
|
||||
return (
|
||||
scanner.rescanModuleSource() === Token.ModuleSource &&
|
||||
!scanner.stringIsUnterminated &&
|
||||
scanner.scan() === Token.ExclamationToken &&
|
||||
scanner.scan() === Token.EofToken
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,8 +187,12 @@ export class DeclarationReference {
|
|||
return this._source === source ? this : new DeclarationReference(source, this._navigation, this._symbol);
|
||||
}
|
||||
|
||||
public withNavigation(navigation: Navigation.Locals | Navigation.Exports | undefined): DeclarationReference {
|
||||
return this._navigation === navigation ? this : new DeclarationReference(this._source, navigation, this._symbol);
|
||||
public withNavigation(
|
||||
navigation: Navigation.Locals | Navigation.Exports | undefined
|
||||
): DeclarationReference {
|
||||
return this._navigation === navigation
|
||||
? this
|
||||
: new DeclarationReference(this._source, navigation, this._symbol);
|
||||
}
|
||||
|
||||
public withSymbol(symbol: SymbolReference | undefined): DeclarationReference {
|
||||
|
@ -190,8 +200,9 @@ export class DeclarationReference {
|
|||
}
|
||||
|
||||
public withComponentPath(componentPath: ComponentPath): DeclarationReference {
|
||||
return this.withSymbol(this.symbol ? this.symbol.withComponentPath(componentPath) :
|
||||
new SymbolReference(componentPath));
|
||||
return this.withSymbol(
|
||||
this.symbol ? this.symbol.withComponentPath(componentPath) : new SymbolReference(componentPath)
|
||||
);
|
||||
}
|
||||
|
||||
public withMeaning(meaning: Meaning | undefined): DeclarationReference {
|
||||
|
@ -226,9 +237,10 @@ export class DeclarationReference {
|
|||
}
|
||||
|
||||
public toString(): string {
|
||||
const navigation: string = this._source instanceof ModuleSource
|
||||
&& this._symbol
|
||||
&& this.navigation === Navigation.Locals ? '~' : '';
|
||||
const navigation: string =
|
||||
this._source instanceof ModuleSource && this._symbol && this.navigation === Navigation.Locals
|
||||
? '~'
|
||||
: '';
|
||||
return `${this.source || ''}${navigation}${this.symbol || ''}`;
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +266,8 @@ export class ModuleSource {
|
|||
private _pathComponents: IParsedPackage | undefined;
|
||||
|
||||
public constructor(path: string, userEscaped: boolean = true) {
|
||||
this.escapedPath = this instanceof ParsedModuleSource ? path : escapeModuleSourceIfNeeded(path, userEscaped);
|
||||
this.escapedPath =
|
||||
this instanceof ParsedModuleSource ? path : escapeModuleSourceIfNeeded(path, userEscaped);
|
||||
}
|
||||
|
||||
public get path(): string {
|
||||
|
@ -278,9 +291,11 @@ export class ModuleSource {
|
|||
return this._getOrParsePathComponents().importPath || '';
|
||||
}
|
||||
|
||||
public static fromScopedPackage(scopeName: string | undefined, unscopedPackageName: string, importPath?: string):
|
||||
ModuleSource {
|
||||
|
||||
public static fromScopedPackage(
|
||||
scopeName: string | undefined,
|
||||
unscopedPackageName: string,
|
||||
importPath?: string
|
||||
): ModuleSource {
|
||||
let packageName: string = unscopedPackageName;
|
||||
if (scopeName) {
|
||||
if (scopeName.charAt(0) === '@') {
|
||||
|
@ -302,7 +317,6 @@ export class ModuleSource {
|
|||
packageName: string,
|
||||
importPath?: string
|
||||
): ModuleSource {
|
||||
|
||||
if (!parsed) {
|
||||
throw new Error('Parsed package must be provided.');
|
||||
}
|
||||
|
@ -349,8 +363,7 @@ export class ModuleSource {
|
|||
}
|
||||
}
|
||||
|
||||
class ParsedModuleSource extends ModuleSource {
|
||||
}
|
||||
class ParsedModuleSource extends ModuleSource {}
|
||||
|
||||
// matches the following:
|
||||
// 'foo' -> ["foo", "foo", undefined, "foo", undefined]
|
||||
|
@ -398,8 +411,7 @@ function parsePackageName(text: string): IParsedPackage | null {
|
|||
export class GlobalSource {
|
||||
public static readonly instance: GlobalSource = new GlobalSource();
|
||||
|
||||
private constructor() {
|
||||
}
|
||||
private constructor() {}
|
||||
|
||||
public toString(): string {
|
||||
return '!';
|
||||
|
@ -409,10 +421,7 @@ export class GlobalSource {
|
|||
/**
|
||||
* @beta
|
||||
*/
|
||||
export type Component =
|
||||
| ComponentString
|
||||
| ComponentReference
|
||||
;
|
||||
export type Component = ComponentString | ComponentReference;
|
||||
|
||||
/**
|
||||
* @beta
|
||||
|
@ -433,11 +442,7 @@ export namespace Component {
|
|||
/**
|
||||
* @beta
|
||||
*/
|
||||
export type ComponentLike =
|
||||
| Component
|
||||
| DeclarationReference
|
||||
| string
|
||||
;
|
||||
export type ComponentLike = Component | DeclarationReference | string;
|
||||
|
||||
/**
|
||||
* @beta
|
||||
|
@ -454,8 +459,7 @@ export class ComponentString {
|
|||
}
|
||||
}
|
||||
|
||||
class ParsedComponentString extends ComponentString {
|
||||
}
|
||||
class ParsedComponentString extends ComponentString {}
|
||||
|
||||
/**
|
||||
* @beta
|
||||
|
@ -486,10 +490,7 @@ export class ComponentReference {
|
|||
/**
|
||||
* @beta
|
||||
*/
|
||||
export type ComponentPath =
|
||||
| ComponentRoot
|
||||
| ComponentNavigation
|
||||
;
|
||||
export type ComponentPath = ComponentRoot | ComponentNavigation;
|
||||
|
||||
/**
|
||||
* @beta
|
||||
|
@ -501,7 +502,11 @@ export abstract class ComponentPathBase {
|
|||
this.component = component;
|
||||
}
|
||||
|
||||
public addNavigationStep(this: ComponentPath, navigation: Navigation, component: ComponentLike): ComponentPath {
|
||||
public addNavigationStep(
|
||||
this: ComponentPath,
|
||||
navigation: Navigation,
|
||||
component: ComponentLike
|
||||
): ComponentPath {
|
||||
// tslint:disable-next-line:no-use-before-declare
|
||||
return new ComponentNavigation(this, navigation, Component.from(component));
|
||||
}
|
||||
|
@ -540,12 +545,15 @@ export class ComponentNavigation extends ComponentPathBase {
|
|||
}
|
||||
|
||||
public withNavigation(navigation: Navigation): ComponentNavigation {
|
||||
return this.navigation === navigation ? this : new ComponentNavigation(this.parent, navigation, this.component);
|
||||
return this.navigation === navigation
|
||||
? this
|
||||
: new ComponentNavigation(this.parent, navigation, this.component);
|
||||
}
|
||||
|
||||
public withComponent(component: ComponentLike): ComponentNavigation {
|
||||
return this.component === component ? this :
|
||||
new ComponentNavigation(this.parent, this.navigation, Component.from(component));
|
||||
return this.component === component
|
||||
? this
|
||||
: new ComponentNavigation(this.parent, this.navigation, Component.from(component));
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
|
@ -557,20 +565,20 @@ export class ComponentNavigation extends ComponentPathBase {
|
|||
* @beta
|
||||
*/
|
||||
export const enum Meaning {
|
||||
Class = 'class', // SymbolFlags.Class
|
||||
Interface = 'interface', // SymbolFlags.Interface
|
||||
TypeAlias = 'type', // SymbolFlags.TypeAlias
|
||||
Enum = 'enum', // SymbolFlags.Enum
|
||||
Namespace = 'namespace', // SymbolFlags.Module
|
||||
Function = 'function', // SymbolFlags.Function
|
||||
Variable = 'var', // SymbolFlags.Variable
|
||||
Constructor = 'constructor', // SymbolFlags.Constructor
|
||||
Member = 'member', // SymbolFlags.ClassMember | SymbolFlags.EnumMember
|
||||
Event = 'event', //
|
||||
CallSignature = 'call', // SymbolFlags.Signature (for __call)
|
||||
ConstructSignature = 'new', // SymbolFlags.Signature (for __new)
|
||||
IndexSignature = 'index', // SymbolFlags.Signature (for __index)
|
||||
ComplexType = 'complex' // Any complex type
|
||||
Class = 'class', // SymbolFlags.Class
|
||||
Interface = 'interface', // SymbolFlags.Interface
|
||||
TypeAlias = 'type', // SymbolFlags.TypeAlias
|
||||
Enum = 'enum', // SymbolFlags.Enum
|
||||
Namespace = 'namespace', // SymbolFlags.Module
|
||||
Function = 'function', // SymbolFlags.Function
|
||||
Variable = 'var', // SymbolFlags.Variable
|
||||
Constructor = 'constructor', // SymbolFlags.Constructor
|
||||
Member = 'member', // SymbolFlags.ClassMember | SymbolFlags.EnumMember
|
||||
Event = 'event', //
|
||||
CallSignature = 'call', // SymbolFlags.Signature (for __call)
|
||||
ConstructSignature = 'new', // SymbolFlags.Signature (for __new)
|
||||
IndexSignature = 'index', // SymbolFlags.Signature (for __index)
|
||||
ComplexType = 'complex' // Any complex type
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -590,7 +598,10 @@ export class SymbolReference {
|
|||
public readonly meaning: Meaning | undefined;
|
||||
public readonly overloadIndex: number | undefined;
|
||||
|
||||
public constructor(component: ComponentPath | undefined, { meaning, overloadIndex }: ISymbolReferenceOptions = {}) {
|
||||
public constructor(
|
||||
component: ComponentPath | undefined,
|
||||
{ meaning, overloadIndex }: ISymbolReferenceOptions = {}
|
||||
) {
|
||||
this.componentPath = component;
|
||||
this.overloadIndex = overloadIndex;
|
||||
this.meaning = meaning;
|
||||
|
@ -601,29 +612,35 @@ export class SymbolReference {
|
|||
}
|
||||
|
||||
public withComponentPath(componentPath: ComponentPath | undefined): SymbolReference {
|
||||
return this.componentPath === componentPath ? this : new SymbolReference(componentPath, {
|
||||
meaning: this.meaning,
|
||||
overloadIndex: this.overloadIndex
|
||||
});
|
||||
return this.componentPath === componentPath
|
||||
? this
|
||||
: new SymbolReference(componentPath, {
|
||||
meaning: this.meaning,
|
||||
overloadIndex: this.overloadIndex
|
||||
});
|
||||
}
|
||||
|
||||
public withMeaning(meaning: Meaning | undefined): SymbolReference {
|
||||
return this.meaning === meaning ? this : new SymbolReference(this.componentPath, {
|
||||
meaning,
|
||||
overloadIndex: this.overloadIndex
|
||||
});
|
||||
return this.meaning === meaning
|
||||
? this
|
||||
: new SymbolReference(this.componentPath, {
|
||||
meaning,
|
||||
overloadIndex: this.overloadIndex
|
||||
});
|
||||
}
|
||||
|
||||
public withOverloadIndex(overloadIndex: number | undefined): SymbolReference {
|
||||
return this.overloadIndex === overloadIndex ? this : new SymbolReference(this.componentPath, {
|
||||
meaning: this.meaning,
|
||||
overloadIndex
|
||||
});
|
||||
return this.overloadIndex === overloadIndex
|
||||
? this
|
||||
: new SymbolReference(this.componentPath, {
|
||||
meaning: this.meaning,
|
||||
overloadIndex
|
||||
});
|
||||
}
|
||||
|
||||
public addNavigationStep(navigation: Navigation, component: ComponentLike): SymbolReference {
|
||||
if (!this.componentPath) {
|
||||
throw new Error('Cannot add a navigation step to an empty symbol reference.');
|
||||
throw new Error('Cannot add a navigation step to an empty symbol reference.');
|
||||
}
|
||||
return new SymbolReference(this.componentPath.addNavigationStep(navigation, component));
|
||||
}
|
||||
|
@ -645,75 +662,108 @@ const enum Token {
|
|||
None,
|
||||
EofToken,
|
||||
// Punctuator
|
||||
OpenBraceToken, // '{'
|
||||
CloseBraceToken, // '}'
|
||||
OpenParenToken, // '('
|
||||
CloseParenToken, // ')'
|
||||
OpenBracketToken, // '['
|
||||
CloseBracketToken, // ']'
|
||||
ExclamationToken, // '!'
|
||||
DotToken, // '.'
|
||||
HashToken, // '#'
|
||||
TildeToken, // '~'
|
||||
ColonToken, // ':'
|
||||
CommaToken, // ','
|
||||
AtToken, // '@'
|
||||
DecimalDigits, // '12345'
|
||||
String, // '"abc"'
|
||||
Text, // 'abc'
|
||||
ModuleSource, // 'abc/def!' (excludes '!')
|
||||
OpenBraceToken, // '{'
|
||||
CloseBraceToken, // '}'
|
||||
OpenParenToken, // '('
|
||||
CloseParenToken, // ')'
|
||||
OpenBracketToken, // '['
|
||||
CloseBracketToken, // ']'
|
||||
ExclamationToken, // '!'
|
||||
DotToken, // '.'
|
||||
HashToken, // '#'
|
||||
TildeToken, // '~'
|
||||
ColonToken, // ':'
|
||||
CommaToken, // ','
|
||||
AtToken, // '@'
|
||||
DecimalDigits, // '12345'
|
||||
String, // '"abc"'
|
||||
Text, // 'abc'
|
||||
ModuleSource, // 'abc/def!' (excludes '!')
|
||||
// Keywords
|
||||
ClassKeyword, // 'class'
|
||||
InterfaceKeyword, // 'interface'
|
||||
TypeKeyword, // 'type'
|
||||
EnumKeyword, // 'enum'
|
||||
NamespaceKeyword, // 'namespace'
|
||||
FunctionKeyword, // 'function'
|
||||
VarKeyword, // 'var'
|
||||
ConstructorKeyword, // 'constructor'
|
||||
MemberKeyword, // 'member'
|
||||
EventKeyword, // 'event'
|
||||
CallKeyword, // 'call'
|
||||
NewKeyword, // 'new'
|
||||
IndexKeyword, // 'index'
|
||||
ComplexKeyword // 'complex'
|
||||
ClassKeyword, // 'class'
|
||||
InterfaceKeyword, // 'interface'
|
||||
TypeKeyword, // 'type'
|
||||
EnumKeyword, // 'enum'
|
||||
NamespaceKeyword, // 'namespace'
|
||||
FunctionKeyword, // 'function'
|
||||
VarKeyword, // 'var'
|
||||
ConstructorKeyword, // 'constructor'
|
||||
MemberKeyword, // 'member'
|
||||
EventKeyword, // 'event'
|
||||
CallKeyword, // 'call'
|
||||
NewKeyword, // 'new'
|
||||
IndexKeyword, // 'index'
|
||||
ComplexKeyword // 'complex'
|
||||
}
|
||||
|
||||
function tokenToString(token: Token): string {
|
||||
switch (token) {
|
||||
case Token.OpenBraceToken: return '{';
|
||||
case Token.CloseBraceToken: return '}';
|
||||
case Token.OpenParenToken: return '(';
|
||||
case Token.CloseParenToken: return ')';
|
||||
case Token.OpenBracketToken: return '[';
|
||||
case Token.CloseBracketToken: return ']';
|
||||
case Token.ExclamationToken: return '!';
|
||||
case Token.DotToken: return '.';
|
||||
case Token.HashToken: return '#';
|
||||
case Token.TildeToken: return '~';
|
||||
case Token.ColonToken: return ':';
|
||||
case Token.CommaToken: return ',';
|
||||
case Token.AtToken: return '@';
|
||||
case Token.ClassKeyword: return 'class';
|
||||
case Token.InterfaceKeyword: return 'interface';
|
||||
case Token.TypeKeyword: return 'type';
|
||||
case Token.EnumKeyword: return 'enum';
|
||||
case Token.NamespaceKeyword: return 'namespace';
|
||||
case Token.FunctionKeyword: return 'function';
|
||||
case Token.VarKeyword: return 'var';
|
||||
case Token.ConstructorKeyword: return 'constructor';
|
||||
case Token.MemberKeyword: return 'member';
|
||||
case Token.EventKeyword: return 'event';
|
||||
case Token.CallKeyword: return 'call';
|
||||
case Token.NewKeyword: return 'new';
|
||||
case Token.IndexKeyword: return 'index';
|
||||
case Token.ComplexKeyword: return 'complex';
|
||||
case Token.None: return '<none>';
|
||||
case Token.EofToken: return '<eof>';
|
||||
case Token.DecimalDigits: return '<decimal digits>';
|
||||
case Token.String: return '<string>';
|
||||
case Token.Text: return '<text>';
|
||||
case Token.ModuleSource: return '<module source>';
|
||||
case Token.OpenBraceToken:
|
||||
return '{';
|
||||
case Token.CloseBraceToken:
|
||||
return '}';
|
||||
case Token.OpenParenToken:
|
||||
return '(';
|
||||
case Token.CloseParenToken:
|
||||
return ')';
|
||||
case Token.OpenBracketToken:
|
||||
return '[';
|
||||
case Token.CloseBracketToken:
|
||||
return ']';
|
||||
case Token.ExclamationToken:
|
||||
return '!';
|
||||
case Token.DotToken:
|
||||
return '.';
|
||||
case Token.HashToken:
|
||||
return '#';
|
||||
case Token.TildeToken:
|
||||
return '~';
|
||||
case Token.ColonToken:
|
||||
return ':';
|
||||
case Token.CommaToken:
|
||||
return ',';
|
||||
case Token.AtToken:
|
||||
return '@';
|
||||
case Token.ClassKeyword:
|
||||
return 'class';
|
||||
case Token.InterfaceKeyword:
|
||||
return 'interface';
|
||||
case Token.TypeKeyword:
|
||||
return 'type';
|
||||
case Token.EnumKeyword:
|
||||
return 'enum';
|
||||
case Token.NamespaceKeyword:
|
||||
return 'namespace';
|
||||
case Token.FunctionKeyword:
|
||||
return 'function';
|
||||
case Token.VarKeyword:
|
||||
return 'var';
|
||||
case Token.ConstructorKeyword:
|
||||
return 'constructor';
|
||||
case Token.MemberKeyword:
|
||||
return 'member';
|
||||
case Token.EventKeyword:
|
||||
return 'event';
|
||||
case Token.CallKeyword:
|
||||
return 'call';
|
||||
case Token.NewKeyword:
|
||||
return 'new';
|
||||
case Token.IndexKeyword:
|
||||
return 'index';
|
||||
case Token.ComplexKeyword:
|
||||
return 'complex';
|
||||
case Token.None:
|
||||
return '<none>';
|
||||
case Token.EofToken:
|
||||
return '<eof>';
|
||||
case Token.DecimalDigits:
|
||||
return '<decimal digits>';
|
||||
case Token.String:
|
||||
return '<string>';
|
||||
case Token.Text:
|
||||
return '<text>';
|
||||
case Token.ModuleSource:
|
||||
return '<module source>';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,7 +810,9 @@ class Scanner {
|
|||
const stringIsUnterminated: boolean = this._stringIsUnterminated;
|
||||
let accepted: boolean = false;
|
||||
try {
|
||||
const accept: () => void = () => { accepted = true; };
|
||||
const accept: () => void = () => {
|
||||
accepted = true;
|
||||
};
|
||||
return cb(accept);
|
||||
} finally {
|
||||
if (!accepted) {
|
||||
|
@ -780,29 +832,42 @@ class Scanner {
|
|||
while (!this.eof) {
|
||||
const ch: string = this._text.charAt(this._pos++);
|
||||
switch (ch) {
|
||||
case '{': return this._token = Token.OpenBraceToken;
|
||||
case '}': return this._token = Token.CloseBraceToken;
|
||||
case '(': return this._token = Token.OpenParenToken;
|
||||
case ')': return this._token = Token.CloseParenToken;
|
||||
case '[': return this._token = Token.OpenBracketToken;
|
||||
case ']': return this._token = Token.CloseBracketToken;
|
||||
case '!': return this._token = Token.ExclamationToken;
|
||||
case '.': return this._token = Token.DotToken;
|
||||
case '#': return this._token = Token.HashToken;
|
||||
case '~': return this._token = Token.TildeToken;
|
||||
case ':': return this._token = Token.ColonToken;
|
||||
case ',': return this._token = Token.CommaToken;
|
||||
case '@': return this._token = Token.AtToken;
|
||||
case '{':
|
||||
return (this._token = Token.OpenBraceToken);
|
||||
case '}':
|
||||
return (this._token = Token.CloseBraceToken);
|
||||
case '(':
|
||||
return (this._token = Token.OpenParenToken);
|
||||
case ')':
|
||||
return (this._token = Token.CloseParenToken);
|
||||
case '[':
|
||||
return (this._token = Token.OpenBracketToken);
|
||||
case ']':
|
||||
return (this._token = Token.CloseBracketToken);
|
||||
case '!':
|
||||
return (this._token = Token.ExclamationToken);
|
||||
case '.':
|
||||
return (this._token = Token.DotToken);
|
||||
case '#':
|
||||
return (this._token = Token.HashToken);
|
||||
case '~':
|
||||
return (this._token = Token.TildeToken);
|
||||
case ':':
|
||||
return (this._token = Token.ColonToken);
|
||||
case ',':
|
||||
return (this._token = Token.CommaToken);
|
||||
case '@':
|
||||
return (this._token = Token.AtToken);
|
||||
case '"':
|
||||
this.scanString();
|
||||
return this._token = Token.String;
|
||||
return (this._token = Token.String);
|
||||
default:
|
||||
this.scanText();
|
||||
return this._token = Token.Text;
|
||||
return (this._token = Token.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._token = Token.EofToken;
|
||||
return (this._token = Token.EofToken);
|
||||
}
|
||||
|
||||
public rescanModuleSource(): Token {
|
||||
|
@ -812,7 +877,7 @@ class Scanner {
|
|||
case Token.EofToken:
|
||||
return this._token;
|
||||
}
|
||||
return this.speculate(accept => {
|
||||
return this.speculate((accept) => {
|
||||
if (!this.eof) {
|
||||
this._pos = this._tokenPos;
|
||||
this._stringIsUnterminated = false;
|
||||
|
@ -824,7 +889,7 @@ class Scanner {
|
|||
return this._token;
|
||||
}
|
||||
accept();
|
||||
return this._token = Token.ModuleSource;
|
||||
return (this._token = Token.ModuleSource);
|
||||
}
|
||||
this._pos++;
|
||||
if (ch === '"') {
|
||||
|
@ -854,20 +919,34 @@ class Scanner {
|
|||
if (this._token === Token.Text) {
|
||||
const tokenText: string = this.tokenText;
|
||||
switch (tokenText) {
|
||||
case 'class': return this._token = Token.ClassKeyword;
|
||||
case 'interface': return this._token = Token.InterfaceKeyword;
|
||||
case 'type': return this._token = Token.TypeKeyword;
|
||||
case 'enum': return this._token = Token.EnumKeyword;
|
||||
case 'namespace': return this._token = Token.NamespaceKeyword;
|
||||
case 'function': return this._token = Token.FunctionKeyword;
|
||||
case 'var': return this._token = Token.VarKeyword;
|
||||
case 'constructor': return this._token = Token.ConstructorKeyword;
|
||||
case 'member': return this._token = Token.MemberKeyword;
|
||||
case 'event': return this._token = Token.EventKeyword;
|
||||
case 'call': return this._token = Token.CallKeyword;
|
||||
case 'new': return this._token = Token.NewKeyword;
|
||||
case 'index': return this._token = Token.IndexKeyword;
|
||||
case 'complex': return this._token = Token.ComplexKeyword;
|
||||
case 'class':
|
||||
return (this._token = Token.ClassKeyword);
|
||||
case 'interface':
|
||||
return (this._token = Token.InterfaceKeyword);
|
||||
case 'type':
|
||||
return (this._token = Token.TypeKeyword);
|
||||
case 'enum':
|
||||
return (this._token = Token.EnumKeyword);
|
||||
case 'namespace':
|
||||
return (this._token = Token.NamespaceKeyword);
|
||||
case 'function':
|
||||
return (this._token = Token.FunctionKeyword);
|
||||
case 'var':
|
||||
return (this._token = Token.VarKeyword);
|
||||
case 'constructor':
|
||||
return (this._token = Token.ConstructorKeyword);
|
||||
case 'member':
|
||||
return (this._token = Token.MemberKeyword);
|
||||
case 'event':
|
||||
return (this._token = Token.EventKeyword);
|
||||
case 'call':
|
||||
return (this._token = Token.CallKeyword);
|
||||
case 'new':
|
||||
return (this._token = Token.NewKeyword);
|
||||
case 'index':
|
||||
return (this._token = Token.IndexKeyword);
|
||||
case 'complex':
|
||||
return (this._token = Token.ComplexKeyword);
|
||||
}
|
||||
}
|
||||
return this._token;
|
||||
|
@ -877,7 +956,7 @@ class Scanner {
|
|||
if (this._token === Token.Text) {
|
||||
const tokenText: string = this.tokenText;
|
||||
if (/^\d+$/.test(tokenText)) {
|
||||
return this._token = Token.DecimalDigits;
|
||||
return (this._token = Token.DecimalDigits);
|
||||
}
|
||||
}
|
||||
return this._token;
|
||||
|
@ -887,7 +966,8 @@ class Scanner {
|
|||
while (!this.eof) {
|
||||
const ch: string = this._text.charAt(this._pos++);
|
||||
switch (ch) {
|
||||
case '"': return;
|
||||
case '"':
|
||||
return;
|
||||
case '\\':
|
||||
this.scanEscapeSequence();
|
||||
break;
|
||||
|
@ -916,39 +996,42 @@ class Scanner {
|
|||
}
|
||||
|
||||
// EscapeSequence:: `0` [lookahead != DecimalDigit]
|
||||
if (ch === '0'
|
||||
&& (this._pos + 1 === this._text.length
|
||||
|| !isDecimalDigit(this._text.charAt(this._pos + 1)))) {
|
||||
if (
|
||||
ch === '0' &&
|
||||
(this._pos + 1 === this._text.length || !isDecimalDigit(this._text.charAt(this._pos + 1)))
|
||||
) {
|
||||
this._pos++;
|
||||
return;
|
||||
}
|
||||
|
||||
// EscapeSequence:: HexEscapeSequence
|
||||
if (ch === 'x'
|
||||
&& this._pos + 3 <= this._text.length
|
||||
&& isHexDigit(this._text.charAt(this._pos + 1))
|
||||
&& isHexDigit(this._text.charAt(this._pos + 2))) {
|
||||
if (
|
||||
ch === 'x' &&
|
||||
this._pos + 3 <= this._text.length &&
|
||||
isHexDigit(this._text.charAt(this._pos + 1)) &&
|
||||
isHexDigit(this._text.charAt(this._pos + 2))
|
||||
) {
|
||||
this._pos += 3;
|
||||
return;
|
||||
}
|
||||
|
||||
// EscapeSequence:: UnicodeEscapeSequence
|
||||
// UnicodeEscapeSequence:: `u` Hex4Digits
|
||||
if (ch === 'u'
|
||||
&& this._pos + 5 <= this._text.length
|
||||
&& isHexDigit(this._text.charAt(this._pos + 1))
|
||||
&& isHexDigit(this._text.charAt(this._pos + 2))
|
||||
&& isHexDigit(this._text.charAt(this._pos + 3))
|
||||
&& isHexDigit(this._text.charAt(this._pos + 4))) {
|
||||
if (
|
||||
ch === 'u' &&
|
||||
this._pos + 5 <= this._text.length &&
|
||||
isHexDigit(this._text.charAt(this._pos + 1)) &&
|
||||
isHexDigit(this._text.charAt(this._pos + 2)) &&
|
||||
isHexDigit(this._text.charAt(this._pos + 3)) &&
|
||||
isHexDigit(this._text.charAt(this._pos + 4))
|
||||
) {
|
||||
this._pos += 5;
|
||||
return;
|
||||
}
|
||||
|
||||
// EscapeSequence:: UnicodeEscapeSequence
|
||||
// UnicodeEscapeSequence:: `u` `{` CodePoint `}`
|
||||
if (ch === 'u'
|
||||
&& this._pos + 4 <= this._text.length
|
||||
&& this._text.charAt(this._pos + 1) === '{') {
|
||||
if (ch === 'u' && this._pos + 4 <= this._text.length && this._text.charAt(this._pos + 1) === '{') {
|
||||
let hexDigits: string = this._text.charAt(this._pos + 2);
|
||||
if (isHexDigit(hexDigits)) {
|
||||
for (let i: number = this._pos + 3; i < this._text.length; i++) {
|
||||
|
@ -1064,7 +1147,10 @@ class Parser {
|
|||
|
||||
private parseRootComponent(): ComponentPath {
|
||||
if (!this.isStartOfComponent()) {
|
||||
return this.fail('Component expected', new ComponentRoot(new ComponentString('', /*userEscaped*/ true)));
|
||||
return this.fail(
|
||||
'Component expected',
|
||||
new ComponentRoot(new ComponentString('', /*userEscaped*/ true))
|
||||
);
|
||||
}
|
||||
|
||||
const component: Component = this.parseComponent();
|
||||
|
@ -1072,7 +1158,7 @@ class Parser {
|
|||
}
|
||||
|
||||
private parseComponentRest(component: ComponentPath): ComponentPath {
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
switch (this.token()) {
|
||||
case Token.DotToken:
|
||||
case Token.HashToken:
|
||||
|
@ -1089,30 +1175,49 @@ class Parser {
|
|||
|
||||
private parseNavigation(): Navigation {
|
||||
switch (this._scanner.token()) {
|
||||
case Token.DotToken: return this._scanner.scan(), Navigation.Exports;
|
||||
case Token.HashToken: return this._scanner.scan(), Navigation.Members;
|
||||
case Token.TildeToken: return this._scanner.scan(), Navigation.Locals;
|
||||
default: return this.fail('Expected \'.\', \'#\', or \'~\'', Navigation.Exports);
|
||||
case Token.DotToken:
|
||||
return this._scanner.scan(), Navigation.Exports;
|
||||
case Token.HashToken:
|
||||
return this._scanner.scan(), Navigation.Members;
|
||||
case Token.TildeToken:
|
||||
return this._scanner.scan(), Navigation.Locals;
|
||||
default:
|
||||
return this.fail("Expected '.', '#', or '~'", Navigation.Exports);
|
||||
}
|
||||
}
|
||||
|
||||
private tryParseMeaning(): Meaning | undefined {
|
||||
switch (this._scanner.rescanMeaning()) {
|
||||
case Token.ClassKeyword: return this._scanner.scan(), Meaning.Class;
|
||||
case Token.InterfaceKeyword: return this._scanner.scan(), Meaning.Interface;
|
||||
case Token.TypeKeyword: return this._scanner.scan(), Meaning.TypeAlias;
|
||||
case Token.EnumKeyword: return this._scanner.scan(), Meaning.Enum;
|
||||
case Token.NamespaceKeyword: return this._scanner.scan(), Meaning.Namespace;
|
||||
case Token.FunctionKeyword: return this._scanner.scan(), Meaning.Function;
|
||||
case Token.VarKeyword: return this._scanner.scan(), Meaning.Variable;
|
||||
case Token.ConstructorKeyword: return this._scanner.scan(), Meaning.Constructor;
|
||||
case Token.MemberKeyword: return this._scanner.scan(), Meaning.Member;
|
||||
case Token.EventKeyword: return this._scanner.scan(), Meaning.Event;
|
||||
case Token.CallKeyword: return this._scanner.scan(), Meaning.CallSignature;
|
||||
case Token.NewKeyword: return this._scanner.scan(), Meaning.ConstructSignature;
|
||||
case Token.IndexKeyword: return this._scanner.scan(), Meaning.IndexSignature;
|
||||
case Token.ComplexKeyword: return this._scanner.scan(), Meaning.ComplexType;
|
||||
default: return undefined;
|
||||
case Token.ClassKeyword:
|
||||
return this._scanner.scan(), Meaning.Class;
|
||||
case Token.InterfaceKeyword:
|
||||
return this._scanner.scan(), Meaning.Interface;
|
||||
case Token.TypeKeyword:
|
||||
return this._scanner.scan(), Meaning.TypeAlias;
|
||||
case Token.EnumKeyword:
|
||||
return this._scanner.scan(), Meaning.Enum;
|
||||
case Token.NamespaceKeyword:
|
||||
return this._scanner.scan(), Meaning.Namespace;
|
||||
case Token.FunctionKeyword:
|
||||
return this._scanner.scan(), Meaning.Function;
|
||||
case Token.VarKeyword:
|
||||
return this._scanner.scan(), Meaning.Variable;
|
||||
case Token.ConstructorKeyword:
|
||||
return this._scanner.scan(), Meaning.Constructor;
|
||||
case Token.MemberKeyword:
|
||||
return this._scanner.scan(), Meaning.Member;
|
||||
case Token.EventKeyword:
|
||||
return this._scanner.scan(), Meaning.Event;
|
||||
case Token.CallKeyword:
|
||||
return this._scanner.scan(), Meaning.CallSignature;
|
||||
case Token.NewKeyword:
|
||||
return this._scanner.scan(), Meaning.ConstructSignature;
|
||||
case Token.IndexKeyword:
|
||||
return this._scanner.scan(), Meaning.IndexSignature;
|
||||
case Token.ComplexKeyword:
|
||||
return this._scanner.scan(), Meaning.ComplexType;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1151,7 +1256,7 @@ class Parser {
|
|||
|
||||
private parseComponentCharacters(): string {
|
||||
let text: string = '';
|
||||
for (; ;) {
|
||||
for (;;) {
|
||||
switch (this._scanner.token()) {
|
||||
case Token.Text:
|
||||
text += this.parseText();
|
||||
|
@ -1224,21 +1329,24 @@ class Parser {
|
|||
|
||||
function formatNavigation(navigation: Navigation | undefined): string {
|
||||
switch (navigation) {
|
||||
case Navigation.Exports: return '.';
|
||||
case Navigation.Members: return '#';
|
||||
case Navigation.Locals: return '~';
|
||||
default: return '';
|
||||
case Navigation.Exports:
|
||||
return '.';
|
||||
case Navigation.Members:
|
||||
return '#';
|
||||
case Navigation.Locals:
|
||||
return '~';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function isCharacterEscapeSequence(ch: string): boolean {
|
||||
return isSingleEscapeCharacter(ch)
|
||||
|| isNonEscapeCharacter(ch);
|
||||
return isSingleEscapeCharacter(ch) || isNonEscapeCharacter(ch);
|
||||
}
|
||||
|
||||
function isSingleEscapeCharacter(ch: string): boolean {
|
||||
switch (ch) {
|
||||
case '\'':
|
||||
case "'":
|
||||
case '"':
|
||||
case '\\':
|
||||
case 'b':
|
||||
|
@ -1254,8 +1362,7 @@ function isSingleEscapeCharacter(ch: string): boolean {
|
|||
}
|
||||
|
||||
function isNonEscapeCharacter(ch: string): boolean {
|
||||
return !isEscapeCharacter(ch)
|
||||
&& !isLineTerminator(ch);
|
||||
return !isEscapeCharacter(ch) && !isLineTerminator(ch);
|
||||
}
|
||||
|
||||
function isEscapeCharacter(ch: string): boolean {
|
||||
|
@ -1264,8 +1371,7 @@ function isEscapeCharacter(ch: string): boolean {
|
|||
case 'u':
|
||||
return true;
|
||||
default:
|
||||
return isSingleEscapeCharacter(ch)
|
||||
|| isDecimalDigit(ch);
|
||||
return isSingleEscapeCharacter(ch) || isDecimalDigit(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1357,4 +1463,4 @@ function escapeModuleSourceIfNeeded(text: string, userEscaped?: boolean): string
|
|||
return text;
|
||||
}
|
||||
return DeclarationReference.escapeModuleSourceString(text);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ describe('parser', () => {
|
|||
expect(ref.symbol!.componentPath!.component.toString()).toBe('[abc.[def]]');
|
||||
});
|
||||
it.each`
|
||||
text | path | navigation | symbol
|
||||
${'abc!'} | ${'abc'} | ${undefined} | ${undefined}
|
||||
${'"abc"!'} | ${'"abc"'} | ${undefined} | ${undefined}
|
||||
${'@microsoft/rush-stack-compiler-3.5!'} | ${'@microsoft/rush-stack-compiler-3.5'} | ${undefined} | ${undefined}
|
||||
${'abc!def'} | ${'abc'} | ${'.'} | ${'def'}
|
||||
${'abc!~def'} | ${'abc'} | ${'~'} | ${'def'}
|
||||
text | path | navigation | symbol
|
||||
${'abc!'} | ${'abc'} | ${undefined} | ${undefined}
|
||||
${'"abc"!'} | ${'"abc"'} | ${undefined} | ${undefined}
|
||||
${'@microsoft/rush-stack-compiler-3.5!'} | ${'@microsoft/rush-stack-compiler-3.5'} | ${undefined} | ${undefined}
|
||||
${'abc!def'} | ${'abc'} | ${'.'} | ${'def'}
|
||||
${'abc!~def'} | ${'abc'} | ${'~'} | ${'def'}
|
||||
`('parse module source $text', ({ text, path, navigation, symbol }) => {
|
||||
const ref: DeclarationReference = DeclarationReference.parse(text);
|
||||
expect(ref.source).toBeInstanceOf(ModuleSource);
|
||||
|
@ -63,21 +63,21 @@ describe('parser', () => {
|
|||
expect(ref.symbol!.componentPath!.component.toString()).toBe(symbol);
|
||||
});
|
||||
it.each`
|
||||
text | meaning
|
||||
${'a:class'} | ${Meaning.Class}
|
||||
${'a:interface'} | ${Meaning.Interface}
|
||||
${'a:type'} | ${Meaning.TypeAlias}
|
||||
${'a:enum'} | ${Meaning.Enum}
|
||||
${'a:namespace'} | ${Meaning.Namespace}
|
||||
${'a:function'} | ${Meaning.Function}
|
||||
${'a:var'} | ${Meaning.Variable}
|
||||
${'a:constructor'} | ${Meaning.Constructor}
|
||||
${'a:member'} | ${Meaning.Member}
|
||||
${'a:event'} | ${Meaning.Event}
|
||||
${'a:call'} | ${Meaning.CallSignature}
|
||||
${'a:new'} | ${Meaning.ConstructSignature}
|
||||
${'a:index'} | ${Meaning.IndexSignature}
|
||||
${'a:complex'} | ${Meaning.ComplexType}
|
||||
text | meaning
|
||||
${'a:class'} | ${Meaning.Class}
|
||||
${'a:interface'} | ${Meaning.Interface}
|
||||
${'a:type'} | ${Meaning.TypeAlias}
|
||||
${'a:enum'} | ${Meaning.Enum}
|
||||
${'a:namespace'} | ${Meaning.Namespace}
|
||||
${'a:function'} | ${Meaning.Function}
|
||||
${'a:var'} | ${Meaning.Variable}
|
||||
${'a:constructor'} | ${Meaning.Constructor}
|
||||
${'a:member'} | ${Meaning.Member}
|
||||
${'a:event'} | ${Meaning.Event}
|
||||
${'a:call'} | ${Meaning.CallSignature}
|
||||
${'a:new'} | ${Meaning.ConstructSignature}
|
||||
${'a:index'} | ${Meaning.IndexSignature}
|
||||
${'a:complex'} | ${Meaning.ComplexType}
|
||||
`('parse meaning $meaning', ({ text, meaning }) => {
|
||||
const ref: DeclarationReference = DeclarationReference.parse(text);
|
||||
expect(ref.symbol!.meaning).toBe(meaning);
|
||||
|
@ -119,8 +119,10 @@ describe('parser', () => {
|
|||
});
|
||||
});
|
||||
it('add navigation step', () => {
|
||||
const ref: DeclarationReference = DeclarationReference.empty()
|
||||
.addNavigationStep(Navigation.Members, ComponentReference.parse('[Symbol.iterator]'));
|
||||
const ref: DeclarationReference = DeclarationReference.empty().addNavigationStep(
|
||||
Navigation.Members,
|
||||
ComponentReference.parse('[Symbol.iterator]')
|
||||
);
|
||||
const symbol: SymbolReference = ref.symbol!;
|
||||
expect(symbol).toBeInstanceOf(SymbolReference);
|
||||
expect(symbol.componentPath).toBeDefined();
|
||||
|
@ -128,77 +130,77 @@ it('add navigation step', () => {
|
|||
});
|
||||
describe('DeclarationReference', () => {
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${true}
|
||||
${'a'} | ${true}
|
||||
${'a.b'} | ${false}
|
||||
${'a~b'} | ${false}
|
||||
${'a#b'} | ${false}
|
||||
${'a:class'} | ${false}
|
||||
${'a!'} | ${false}
|
||||
${'@a'} | ${false}
|
||||
${'a@'} | ${false}
|
||||
${'['} | ${false}
|
||||
${']'} | ${false}
|
||||
${'{'} | ${false}
|
||||
${'}'} | ${false}
|
||||
${'('} | ${false}
|
||||
${')'} | ${false}
|
||||
${'[a]'} | ${false}
|
||||
${'[a.b]'} | ${false}
|
||||
${'[a!b]'} | ${false}
|
||||
${'""'} | ${true}
|
||||
${'"a"'} | ${true}
|
||||
${'"a.b"'} | ${true}
|
||||
${'"a~b"'} | ${true}
|
||||
${'"a#b"'} | ${true}
|
||||
${'"a:class"'} | ${true}
|
||||
${'"a!"'} | ${true}
|
||||
${'"@a"'} | ${true}
|
||||
${'"a@"'} | ${true}
|
||||
${'"["'} | ${true}
|
||||
${'"]"'} | ${true}
|
||||
${'"{"'} | ${true}
|
||||
${'"}"'} | ${true}
|
||||
${'"("'} | ${true}
|
||||
${'")"'} | ${true}
|
||||
text | expected
|
||||
${''} | ${true}
|
||||
${'a'} | ${true}
|
||||
${'a.b'} | ${false}
|
||||
${'a~b'} | ${false}
|
||||
${'a#b'} | ${false}
|
||||
${'a:class'} | ${false}
|
||||
${'a!'} | ${false}
|
||||
${'@a'} | ${false}
|
||||
${'a@'} | ${false}
|
||||
${'['} | ${false}
|
||||
${']'} | ${false}
|
||||
${'{'} | ${false}
|
||||
${'}'} | ${false}
|
||||
${'('} | ${false}
|
||||
${')'} | ${false}
|
||||
${'[a]'} | ${false}
|
||||
${'[a.b]'} | ${false}
|
||||
${'[a!b]'} | ${false}
|
||||
${'""'} | ${true}
|
||||
${'"a"'} | ${true}
|
||||
${'"a.b"'} | ${true}
|
||||
${'"a~b"'} | ${true}
|
||||
${'"a#b"'} | ${true}
|
||||
${'"a:class"'} | ${true}
|
||||
${'"a!"'} | ${true}
|
||||
${'"@a"'} | ${true}
|
||||
${'"a@"'} | ${true}
|
||||
${'"["'} | ${true}
|
||||
${'"]"'} | ${true}
|
||||
${'"{"'} | ${true}
|
||||
${'"}"'} | ${true}
|
||||
${'"("'} | ${true}
|
||||
${'")"'} | ${true}
|
||||
`('isWellFormedComponentString($text)', ({ text, expected }) => {
|
||||
expect(DeclarationReference.isWellFormedComponentString(text)).toBe(expected);
|
||||
});
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${'""'}
|
||||
${'a'} | ${'a'}
|
||||
${'a.b'} | ${'"a.b"'}
|
||||
${'a~b'} | ${'"a~b"'}
|
||||
${'a#b'} | ${'"a#b"'}
|
||||
${'a:class'} | ${'"a:class"'}
|
||||
${'a!'} | ${'"a!"'}
|
||||
${'@a'} | ${'"@a"'}
|
||||
${'a@'} | ${'"a@"'}
|
||||
${'['} | ${'"["'}
|
||||
${']'} | ${'"]"'}
|
||||
${'{'} | ${'"{"'}
|
||||
${'}'} | ${'"}"'}
|
||||
${'('} | ${'"("'}
|
||||
${')'} | ${'")"'}
|
||||
${'[a]'} | ${'"[a]"'}
|
||||
${'[a.b]'} | ${'"[a.b]"'}
|
||||
${'[a!b]'} | ${'"[a!b]"'}
|
||||
${'""'} | ${'"\\\"\\\""'}
|
||||
${'"a"'} | ${'"\\\"a\\\""'}
|
||||
text | expected
|
||||
${''} | ${'""'}
|
||||
${'a'} | ${'a'}
|
||||
${'a.b'} | ${'"a.b"'}
|
||||
${'a~b'} | ${'"a~b"'}
|
||||
${'a#b'} | ${'"a#b"'}
|
||||
${'a:class'} | ${'"a:class"'}
|
||||
${'a!'} | ${'"a!"'}
|
||||
${'@a'} | ${'"@a"'}
|
||||
${'a@'} | ${'"a@"'}
|
||||
${'['} | ${'"["'}
|
||||
${']'} | ${'"]"'}
|
||||
${'{'} | ${'"{"'}
|
||||
${'}'} | ${'"}"'}
|
||||
${'('} | ${'"("'}
|
||||
${')'} | ${'")"'}
|
||||
${'[a]'} | ${'"[a]"'}
|
||||
${'[a.b]'} | ${'"[a.b]"'}
|
||||
${'[a!b]'} | ${'"[a!b]"'}
|
||||
${'""'} | ${'"\\"\\""'}
|
||||
${'"a"'} | ${'"\\"a\\""'}
|
||||
`('escapeComponentString($text)', ({ text, expected }) => {
|
||||
expect(DeclarationReference.escapeComponentString(text)).toBe(expected);
|
||||
});
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${''}
|
||||
${'""'} | ${''}
|
||||
${'a'} | ${'a'}
|
||||
${'"a"'} | ${'a'}
|
||||
${'"a.b"'} | ${'a.b'}
|
||||
${'"\\"\\""'} | ${'""'}
|
||||
${'"\\"a\\""'} | ${'"a"'}
|
||||
text | expected
|
||||
${''} | ${''}
|
||||
${'""'} | ${''}
|
||||
${'a'} | ${'a'}
|
||||
${'"a"'} | ${'a'}
|
||||
${'"a.b"'} | ${'a.b'}
|
||||
${'"\\"\\""'} | ${'""'}
|
||||
${'"\\"a\\""'} | ${'"a"'}
|
||||
`('unescapeComponentString($text)', ({ text, expected }) => {
|
||||
if (expected === undefined) {
|
||||
expect(() => DeclarationReference.unescapeComponentString(text)).toThrow();
|
||||
|
@ -207,79 +209,79 @@ describe('DeclarationReference', () => {
|
|||
}
|
||||
});
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${false}
|
||||
${'a'} | ${true}
|
||||
${'a.b'} | ${true}
|
||||
${'a~b'} | ${true}
|
||||
${'a#b'} | ${true}
|
||||
${'a:class'} | ${true}
|
||||
${'a!'} | ${false}
|
||||
${'@a'} | ${true}
|
||||
${'a@'} | ${true}
|
||||
${'['} | ${true}
|
||||
${']'} | ${true}
|
||||
${'{'} | ${true}
|
||||
${'}'} | ${true}
|
||||
${'('} | ${true}
|
||||
${')'} | ${true}
|
||||
${'[a]'} | ${true}
|
||||
${'[a.b]'} | ${true}
|
||||
${'[a!b]'} | ${false}
|
||||
${'""'} | ${true}
|
||||
${'"a"'} | ${true}
|
||||
${'"a.b"'} | ${true}
|
||||
${'"a~b"'} | ${true}
|
||||
${'"a#b"'} | ${true}
|
||||
${'"a:class"'} | ${true}
|
||||
${'"a!"'} | ${true}
|
||||
${'"@a"'} | ${true}
|
||||
${'"a@"'} | ${true}
|
||||
${'"["'} | ${true}
|
||||
${'"]"'} | ${true}
|
||||
${'"{"'} | ${true}
|
||||
${'"}"'} | ${true}
|
||||
${'"("'} | ${true}
|
||||
${'")"'} | ${true}
|
||||
${'"[a!b]"'} | ${true}
|
||||
text | expected
|
||||
${''} | ${false}
|
||||
${'a'} | ${true}
|
||||
${'a.b'} | ${true}
|
||||
${'a~b'} | ${true}
|
||||
${'a#b'} | ${true}
|
||||
${'a:class'} | ${true}
|
||||
${'a!'} | ${false}
|
||||
${'@a'} | ${true}
|
||||
${'a@'} | ${true}
|
||||
${'['} | ${true}
|
||||
${']'} | ${true}
|
||||
${'{'} | ${true}
|
||||
${'}'} | ${true}
|
||||
${'('} | ${true}
|
||||
${')'} | ${true}
|
||||
${'[a]'} | ${true}
|
||||
${'[a.b]'} | ${true}
|
||||
${'[a!b]'} | ${false}
|
||||
${'""'} | ${true}
|
||||
${'"a"'} | ${true}
|
||||
${'"a.b"'} | ${true}
|
||||
${'"a~b"'} | ${true}
|
||||
${'"a#b"'} | ${true}
|
||||
${'"a:class"'} | ${true}
|
||||
${'"a!"'} | ${true}
|
||||
${'"@a"'} | ${true}
|
||||
${'"a@"'} | ${true}
|
||||
${'"["'} | ${true}
|
||||
${'"]"'} | ${true}
|
||||
${'"{"'} | ${true}
|
||||
${'"}"'} | ${true}
|
||||
${'"("'} | ${true}
|
||||
${'")"'} | ${true}
|
||||
${'"[a!b]"'} | ${true}
|
||||
`('isWellFormedModuleSourceString($text)', ({ text, expected }) => {
|
||||
expect(DeclarationReference.isWellFormedModuleSourceString(text)).toBe(expected);
|
||||
});
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${'""'}
|
||||
${'a'} | ${'a'}
|
||||
${'a.b'} | ${'a.b'}
|
||||
${'a~b'} | ${'a~b'}
|
||||
${'a#b'} | ${'a#b'}
|
||||
${'a:class'} | ${'a:class'}
|
||||
${'a!'} | ${'"a!"'}
|
||||
${'@a'} | ${'@a'}
|
||||
${'a@'} | ${'a@'}
|
||||
${'['} | ${'['}
|
||||
${']'} | ${']'}
|
||||
${'{'} | ${'{'}
|
||||
${'}'} | ${'}'}
|
||||
${'('} | ${'('}
|
||||
${')'} | ${')'}
|
||||
${'[a]'} | ${'[a]'}
|
||||
${'[a.b]'} | ${'[a.b]'}
|
||||
${'[a!b]'} | ${'"[a!b]"'}
|
||||
${'""'} | ${'"\\\"\\\""'}
|
||||
${'"a"'} | ${'"\\\"a\\\""'}
|
||||
text | expected
|
||||
${''} | ${'""'}
|
||||
${'a'} | ${'a'}
|
||||
${'a.b'} | ${'a.b'}
|
||||
${'a~b'} | ${'a~b'}
|
||||
${'a#b'} | ${'a#b'}
|
||||
${'a:class'} | ${'a:class'}
|
||||
${'a!'} | ${'"a!"'}
|
||||
${'@a'} | ${'@a'}
|
||||
${'a@'} | ${'a@'}
|
||||
${'['} | ${'['}
|
||||
${']'} | ${']'}
|
||||
${'{'} | ${'{'}
|
||||
${'}'} | ${'}'}
|
||||
${'('} | ${'('}
|
||||
${')'} | ${')'}
|
||||
${'[a]'} | ${'[a]'}
|
||||
${'[a.b]'} | ${'[a.b]'}
|
||||
${'[a!b]'} | ${'"[a!b]"'}
|
||||
${'""'} | ${'"\\"\\""'}
|
||||
${'"a"'} | ${'"\\"a\\""'}
|
||||
`('escapeModuleSourceString($text)', ({ text, expected }) => {
|
||||
expect(DeclarationReference.escapeModuleSourceString(text)).toBe(expected);
|
||||
});
|
||||
it.each`
|
||||
text | expected
|
||||
${''} | ${undefined}
|
||||
${'""'} | ${''}
|
||||
${'a'} | ${'a'}
|
||||
${'"a"'} | ${'a'}
|
||||
${'"a!"'} | ${'a!'}
|
||||
${'"a.b"'} | ${'a.b'}
|
||||
${'"\\"\\""'} | ${'""'}
|
||||
${'"\\"a\\""'} | ${'"a"'}
|
||||
text | expected
|
||||
${''} | ${undefined}
|
||||
${'""'} | ${''}
|
||||
${'a'} | ${'a'}
|
||||
${'"a"'} | ${'a'}
|
||||
${'"a!"'} | ${'a!'}
|
||||
${'"a.b"'} | ${'a.b'}
|
||||
${'"\\"\\""'} | ${'""'}
|
||||
${'"\\"a\\""'} | ${'"a"'}
|
||||
`('unescapeModuleSourceString($text)', ({ text, expected }) => {
|
||||
if (expected === undefined) {
|
||||
expect(() => DeclarationReference.unescapeModuleSourceString(text)).toThrow();
|
||||
|
@ -303,26 +305,28 @@ describe('ModuleSource', () => {
|
|||
expect(source.importPath).toBe(importPath);
|
||||
});
|
||||
it.each`
|
||||
packageName | importPath | text
|
||||
${'a'} | ${undefined} | ${'a'}
|
||||
${'a'} | ${'b'} | ${'a/b'}
|
||||
${'@a/b'} | ${undefined} | ${'@a/b'}
|
||||
${'@a/b'} | ${'c'} | ${'@a/b/c'}
|
||||
packageName | importPath | text
|
||||
${'a'} | ${undefined} | ${'a'}
|
||||
${'a'} | ${'b'} | ${'a/b'}
|
||||
${'@a/b'} | ${undefined} | ${'@a/b'}
|
||||
${'@a/b'} | ${'c'} | ${'@a/b/c'}
|
||||
`('fromPackage($packageName, $importPath)', ({ packageName, importPath, text }) => {
|
||||
const source: ModuleSource = ModuleSource.fromPackage(packageName, importPath);
|
||||
expect(source.path).toBe(text);
|
||||
});
|
||||
it.each`
|
||||
scopeName | unscopedPackageName | importPath | text
|
||||
${''} | ${'a'} | ${undefined} | ${'a'}
|
||||
${''} | ${'a'} | ${'b'} | ${'a/b'}
|
||||
${'a'} | ${'b'} | ${undefined} | ${'@a/b'}
|
||||
${'@a'} | ${'b'} | ${undefined} | ${'@a/b'}
|
||||
${'a'} | ${'b'} | ${'c'} | ${'@a/b/c'}
|
||||
${'@a'} | ${'b'} | ${'c'} | ${'@a/b/c'}
|
||||
`('fromScopedPackage($scopeName, $unscopedPackageName, $importPath)',
|
||||
scopeName | unscopedPackageName | importPath | text
|
||||
${''} | ${'a'} | ${undefined} | ${'a'}
|
||||
${''} | ${'a'} | ${'b'} | ${'a/b'}
|
||||
${'a'} | ${'b'} | ${undefined} | ${'@a/b'}
|
||||
${'@a'} | ${'b'} | ${undefined} | ${'@a/b'}
|
||||
${'a'} | ${'b'} | ${'c'} | ${'@a/b/c'}
|
||||
${'@a'} | ${'b'} | ${'c'} | ${'@a/b/c'}
|
||||
`(
|
||||
'fromScopedPackage($scopeName, $unscopedPackageName, $importPath)',
|
||||
({ scopeName, unscopedPackageName, importPath, text }) => {
|
||||
const source: ModuleSource = ModuleSource.fromScopedPackage(scopeName, unscopedPackageName, importPath);
|
||||
expect(source.path).toBe(text);
|
||||
});
|
||||
});
|
||||
const source: ModuleSource = ModuleSource.fromScopedPackage(scopeName, unscopedPackageName, importPath);
|
||||
expect(source.path).toBe(text);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -30,10 +30,14 @@ export class DocNodeManager {
|
|||
// Example: "_myIdentifier99"
|
||||
private static readonly _nodeKindRegExp: RegExp = /^[_a-z][_a-z0-9]*$/i;
|
||||
|
||||
private readonly _docNodeDefinitionsByKind: Map<string, IRegisteredDocNodeDefinition>
|
||||
= new Map<string, IRegisteredDocNodeDefinition>();
|
||||
private readonly _docNodeDefinitionsByConstructor: Map<DocNodeConstructor, IRegisteredDocNodeDefinition>
|
||||
= new Map<DocNodeConstructor, IRegisteredDocNodeDefinition>();
|
||||
private readonly _docNodeDefinitionsByKind: Map<string, IRegisteredDocNodeDefinition> = new Map<
|
||||
string,
|
||||
IRegisteredDocNodeDefinition
|
||||
>();
|
||||
private readonly _docNodeDefinitionsByConstructor: Map<
|
||||
DocNodeConstructor,
|
||||
IRegisteredDocNodeDefinition
|
||||
> = new Map<DocNodeConstructor, IRegisteredDocNodeDefinition>();
|
||||
|
||||
/**
|
||||
* Registers a list of {@link IDocNodeDefinition} objects to be used with the associated
|
||||
|
@ -47,22 +51,29 @@ export class DocNodeManager {
|
|||
|
||||
for (const definition of definitions) {
|
||||
if (!DocNodeManager._nodeKindRegExp.test(definition.docNodeKind)) {
|
||||
throw new Error(`The DocNode kind ${JSON.stringify(definition.docNodeKind)} is not a valid identifier.`
|
||||
+ ` It must start with an underscore or letter, and be comprised of letters, numbers, and underscores`);
|
||||
throw new Error(
|
||||
`The DocNode kind ${JSON.stringify(definition.docNodeKind)} is not a valid identifier.` +
|
||||
` It must start with an underscore or letter, and be comprised of letters, numbers, and underscores`
|
||||
);
|
||||
}
|
||||
|
||||
let existingDefinition: IRegisteredDocNodeDefinition | undefined
|
||||
= this._docNodeDefinitionsByKind.get(definition.docNodeKind);
|
||||
let existingDefinition: IRegisteredDocNodeDefinition | undefined = this._docNodeDefinitionsByKind.get(
|
||||
definition.docNodeKind
|
||||
);
|
||||
|
||||
if (existingDefinition !== undefined) {
|
||||
throw new Error(`The DocNode kind "${definition.docNodeKind}" was already registered`
|
||||
+ ` by ${existingDefinition.packageName}`);
|
||||
throw new Error(
|
||||
`The DocNode kind "${definition.docNodeKind}" was already registered` +
|
||||
` by ${existingDefinition.packageName}`
|
||||
);
|
||||
}
|
||||
|
||||
existingDefinition = this._docNodeDefinitionsByConstructor.get(definition.constructor);
|
||||
if (existingDefinition !== undefined) {
|
||||
throw new Error(`This DocNode constructor was already registered by ${existingDefinition.packageName}`
|
||||
+ ` as ${existingDefinition.docNodeKind}`);
|
||||
throw new Error(
|
||||
`This DocNode constructor was already registered by ${existingDefinition.packageName}` +
|
||||
` as ${existingDefinition.docNodeKind}`
|
||||
);
|
||||
}
|
||||
|
||||
const newDefinition: IRegisteredDocNodeDefinition = {
|
||||
|
@ -113,7 +124,9 @@ export class DocNodeManager {
|
|||
}
|
||||
|
||||
private _getDefinition(docNodeKind: string): IRegisteredDocNodeDefinition {
|
||||
const definition: IRegisteredDocNodeDefinition | undefined = this._docNodeDefinitionsByKind.get(docNodeKind);
|
||||
const definition: IRegisteredDocNodeDefinition | undefined = this._docNodeDefinitionsByKind.get(
|
||||
docNodeKind
|
||||
);
|
||||
if (definition === undefined) {
|
||||
throw new Error(`The DocNode kind "${docNodeKind}" was not registered with this TSDocConfiguration`);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ export class TSDocConfiguration {
|
|||
* {@link TSDocValidationConfiguration.reportUnsupportedTags} is enabled.
|
||||
*/
|
||||
public get supportedTagDefinitions(): ReadonlyArray<TSDocTagDefinition> {
|
||||
return this.tagDefinitions.filter(x => this.isTagSupported(x));
|
||||
return this.tagDefinitions.filter((x) => this.isTagSupported(x));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,8 +90,9 @@ export class TSDocConfiguration {
|
|||
* Whereas if a tag is "supported", this means it is defined AND the application implements the tag.
|
||||
*/
|
||||
public addTagDefinition(tagDefinition: TSDocTagDefinition): void {
|
||||
const existingDefinition: TSDocTagDefinition | undefined
|
||||
= this._tagDefinitionsByName.get(tagDefinition.tagNameWithUpperCase);
|
||||
const existingDefinition: TSDocTagDefinition | undefined = this._tagDefinitionsByName.get(
|
||||
tagDefinition.tagNameWithUpperCase
|
||||
);
|
||||
|
||||
if (existingDefinition === tagDefinition) {
|
||||
return;
|
||||
|
@ -112,9 +113,10 @@ export class TSDocConfiguration {
|
|||
* @param supported - if specified, calls the {@link TSDocConfiguration.setSupportForTag}
|
||||
* method to mark the definitions as supported or unsupported
|
||||
*/
|
||||
public addTagDefinitions(tagDefinitions: ReadonlyArray<TSDocTagDefinition>,
|
||||
supported?: boolean | undefined): void {
|
||||
|
||||
public addTagDefinitions(
|
||||
tagDefinitions: ReadonlyArray<TSDocTagDefinition>,
|
||||
supported?: boolean | undefined
|
||||
): void {
|
||||
for (const tagDefinition of tagDefinitions) {
|
||||
this.addTagDefinition(tagDefinition);
|
||||
|
||||
|
@ -189,8 +191,9 @@ export class TSDocConfiguration {
|
|||
}
|
||||
|
||||
private _requireTagToBeDefined(tagDefinition: TSDocTagDefinition): void {
|
||||
const matching: TSDocTagDefinition | undefined
|
||||
= this._tagDefinitionsByName.get(tagDefinition.tagNameWithUpperCase);
|
||||
const matching: TSDocTagDefinition | undefined = this._tagDefinitionsByName.get(
|
||||
tagDefinition.tagNameWithUpperCase
|
||||
);
|
||||
if (matching) {
|
||||
if (matching === tagDefinition) {
|
||||
return;
|
||||
|
|
|
@ -77,8 +77,8 @@ export class TSDocTagDefinition {
|
|||
this.tagName = parameters.tagName;
|
||||
this.tagNameWithUpperCase = parameters.tagName.toUpperCase();
|
||||
this.syntaxKind = parameters.syntaxKind;
|
||||
this.standardization = (parameters as ITSDocTagDefinitionInternalParameters).standardization
|
||||
|| Standardization.None;
|
||||
this.standardization =
|
||||
(parameters as ITSDocTagDefinitionInternalParameters).standardization || Standardization.None;
|
||||
this.allowMultiple = !!parameters.allowMultiple;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import { DocNode, DocNodeKind, DocPlainText, DocFencedCode, DocCodeSpan, DocLinkTag, DocEscapedText } from '../nodes';
|
||||
import {
|
||||
DocNode,
|
||||
DocNodeKind,
|
||||
DocPlainText,
|
||||
DocFencedCode,
|
||||
DocCodeSpan,
|
||||
DocLinkTag,
|
||||
DocEscapedText
|
||||
} from '../nodes';
|
||||
|
||||
/**
|
||||
* Renders a DocNode tree as plain text, without any rich text formatting or markup.
|
||||
*/
|
||||
export class PlainTextEmitter {
|
||||
|
||||
/**
|
||||
* Returns true if the specified node contains any text content.
|
||||
*
|
||||
|
@ -30,14 +37,17 @@ export class PlainTextEmitter {
|
|||
* The default value is 1.
|
||||
*/
|
||||
public static hasAnyTextContent(nodes: ReadonlyArray<DocNode>, requiredCharacters?: number): boolean;
|
||||
public static hasAnyTextContent(nodeOrNodes: DocNode | ReadonlyArray<DocNode>, requiredCharacters?: number): boolean {
|
||||
public static hasAnyTextContent(
|
||||
nodeOrNodes: DocNode | ReadonlyArray<DocNode>,
|
||||
requiredCharacters?: number
|
||||
): boolean {
|
||||
if (requiredCharacters === undefined || requiredCharacters < 1) {
|
||||
requiredCharacters = 1; // default
|
||||
}
|
||||
|
||||
let nodes: ReadonlyArray<DocNode>;
|
||||
if (nodeOrNodes instanceof DocNode) {
|
||||
nodes = [ nodeOrNodes ];
|
||||
nodes = [nodeOrNodes];
|
||||
} else {
|
||||
nodes = nodeOrNodes;
|
||||
}
|
||||
|
@ -47,9 +57,11 @@ export class PlainTextEmitter {
|
|||
return foundCharacters >= requiredCharacters;
|
||||
}
|
||||
|
||||
private static _scanTextContent(nodes: ReadonlyArray<DocNode>, requiredCharacters: number,
|
||||
foundCharacters: number): number {
|
||||
|
||||
private static _scanTextContent(
|
||||
nodes: ReadonlyArray<DocNode>,
|
||||
requiredCharacters: number,
|
||||
foundCharacters: number
|
||||
): number {
|
||||
for (const node of nodes) {
|
||||
switch (node.kind) {
|
||||
case DocNodeKind.FencedCode:
|
||||
|
@ -81,7 +93,11 @@ export class PlainTextEmitter {
|
|||
break;
|
||||
}
|
||||
|
||||
foundCharacters += PlainTextEmitter._scanTextContent(node.getChildNodes(), requiredCharacters, foundCharacters);
|
||||
foundCharacters += PlainTextEmitter._scanTextContent(
|
||||
node.getChildNodes(),
|
||||
requiredCharacters,
|
||||
foundCharacters
|
||||
);
|
||||
|
||||
if (foundCharacters >= requiredCharacters) {
|
||||
break;
|
||||
|
@ -97,10 +113,10 @@ export class PlainTextEmitter {
|
|||
let i: number = 0;
|
||||
while (i < length) {
|
||||
switch (s.charCodeAt(i)) {
|
||||
case 32: // space
|
||||
case 9: // tab
|
||||
case 13: // CR
|
||||
case 10: // LF
|
||||
case 32: // space
|
||||
case 9: // tab
|
||||
case 13: // CR
|
||||
case 10: // LF
|
||||
break;
|
||||
default:
|
||||
++count;
|
||||
|
|
|
@ -68,7 +68,10 @@ export class TSDocEmitter {
|
|||
this._renderCompleteObject(output, htmlTag);
|
||||
}
|
||||
|
||||
public renderDeclarationReference(output: IStringBuilder, declarationReference: DocDeclarationReference): void {
|
||||
public renderDeclarationReference(
|
||||
output: IStringBuilder,
|
||||
declarationReference: DocDeclarationReference
|
||||
): void {
|
||||
this._emitCommentFraming = false;
|
||||
this._renderCompleteObject(output, declarationReference);
|
||||
}
|
||||
|
@ -143,7 +146,10 @@ export class TSDocEmitter {
|
|||
const docDeclarationReference: DocDeclarationReference = docNode as DocDeclarationReference;
|
||||
this._writeContent(docDeclarationReference.packageName);
|
||||
this._writeContent(docDeclarationReference.importPath);
|
||||
if (docDeclarationReference.packageName !== undefined || docDeclarationReference.importPath !== undefined) {
|
||||
if (
|
||||
docDeclarationReference.packageName !== undefined ||
|
||||
docDeclarationReference.importPath !== undefined
|
||||
) {
|
||||
this._writeContent('#');
|
||||
}
|
||||
this._renderNodes(docDeclarationReference.memberReferences);
|
||||
|
@ -196,8 +202,8 @@ export class TSDocEmitter {
|
|||
this._writeContent(docHtmlStartTag.name);
|
||||
this._writeContent(docHtmlStartTag.spacingAfterName);
|
||||
|
||||
let needsSpace: boolean = docHtmlStartTag.spacingAfterName === undefined
|
||||
|| docHtmlStartTag.spacingAfterName.length === 0;
|
||||
let needsSpace: boolean =
|
||||
docHtmlStartTag.spacingAfterName === undefined || docHtmlStartTag.spacingAfterName.length === 0;
|
||||
|
||||
for (const attribute of docHtmlStartTag.htmlAttributes) {
|
||||
if (needsSpace) {
|
||||
|
@ -302,7 +308,9 @@ export class TSDocEmitter {
|
|||
break;
|
||||
|
||||
case DocNodeKind.Paragraph:
|
||||
const trimmedParagraph: DocParagraph = DocNodeTransforms.trimSpacesInParagraph(docNode as DocParagraph);
|
||||
const trimmedParagraph: DocParagraph = DocNodeTransforms.trimSpacesInParagraph(
|
||||
docNode as DocParagraph
|
||||
);
|
||||
if (trimmedParagraph.nodes.length > 0) {
|
||||
if (this._hangingParagraph) {
|
||||
// If it's a hanging paragraph, then don't skip a line
|
||||
|
@ -340,9 +348,7 @@ export class TSDocEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
private _renderInlineTag(docInlineTagBase: DocInlineTagBase,
|
||||
writeInlineTagContent: () => void): void {
|
||||
|
||||
private _renderInlineTag(docInlineTagBase: DocInlineTagBase, writeInlineTagContent: () => void): void {
|
||||
this._writeContent('{');
|
||||
this._writeContent(docInlineTagBase.tagName);
|
||||
writeInlineTagContent();
|
||||
|
@ -393,8 +399,7 @@ export class TSDocEmitter {
|
|||
|
||||
if (this._lineState === LineState.Closed) {
|
||||
if (this._emitCommentFraming) {
|
||||
this._output!.append('/**' + this.eol
|
||||
+ ' *');
|
||||
this._output!.append('/**' + this.eol + ' *');
|
||||
}
|
||||
this._lineState = LineState.StartOfLine;
|
||||
}
|
||||
|
@ -414,8 +419,7 @@ export class TSDocEmitter {
|
|||
private _writeNewline(): void {
|
||||
if (this._lineState === LineState.Closed) {
|
||||
if (this._emitCommentFraming) {
|
||||
this._output!.append('/**' + this.eol
|
||||
+ ' *');
|
||||
this._output!.append('/**' + this.eol + ' *');
|
||||
}
|
||||
this._lineState = LineState.StartOfLine;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ function createSnapshot(input: string): {} {
|
|||
const parserContext: ParserContext = tsdocParser.parseString(input);
|
||||
const output: string = parserContext.docComment.emitAsTsdoc();
|
||||
return {
|
||||
errors: parserContext.log.messages.map(x => x.toString()),
|
||||
errors: parserContext.log.messages.map((x) => x.toString()),
|
||||
output: '\n' + output
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
|
||||
export {
|
||||
DocNodeManager,
|
||||
IDocNodeDefinition,
|
||||
DocNodeConstructor
|
||||
} from './configuration/DocNodeManager';
|
||||
export { DocNodeManager, IDocNodeDefinition, DocNodeConstructor } from './configuration/DocNodeManager';
|
||||
export { TSDocConfiguration } from './configuration/TSDocConfiguration';
|
||||
export {
|
||||
ITSDocTagDefinitionParameters,
|
||||
|
|
|
@ -8,31 +8,31 @@ export class BuiltInDocNodes {
|
|||
const docNodeManager: DocNodeManager = configuration.docNodeManager;
|
||||
|
||||
docNodeManager.registerDocNodes('@microsoft/tsdoc', [
|
||||
{ docNodeKind: DocNodeKind.Block, constructor: nodes.DocBlock },
|
||||
{ docNodeKind: DocNodeKind.BlockTag, constructor: nodes.DocBlockTag },
|
||||
{ docNodeKind: DocNodeKind.CodeSpan, constructor: nodes.DocCodeSpan },
|
||||
{ docNodeKind: DocNodeKind.Comment, constructor: nodes.DocComment},
|
||||
{ docNodeKind: DocNodeKind.DeclarationReference, constructor: nodes.DocDeclarationReference },
|
||||
{ docNodeKind: DocNodeKind.ErrorText, constructor: nodes.DocErrorText },
|
||||
{ docNodeKind: DocNodeKind.EscapedText, constructor: nodes.DocEscapedText },
|
||||
{ docNodeKind: DocNodeKind.Excerpt, constructor: nodes.DocExcerpt },
|
||||
{ docNodeKind: DocNodeKind.FencedCode, constructor: nodes.DocFencedCode },
|
||||
{ docNodeKind: DocNodeKind.HtmlAttribute, constructor: nodes.DocHtmlAttribute },
|
||||
{ docNodeKind: DocNodeKind.HtmlEndTag, constructor: nodes.DocHtmlEndTag },
|
||||
{ docNodeKind: DocNodeKind.HtmlStartTag, constructor: nodes.DocHtmlStartTag },
|
||||
{ docNodeKind: DocNodeKind.InheritDocTag, constructor: nodes.DocInheritDocTag },
|
||||
{ docNodeKind: DocNodeKind.InlineTag, constructor: nodes.DocInlineTag },
|
||||
{ docNodeKind: DocNodeKind.LinkTag, constructor: nodes.DocLinkTag },
|
||||
{ docNodeKind: DocNodeKind.MemberIdentifier, constructor: nodes.DocMemberIdentifier },
|
||||
{ docNodeKind: DocNodeKind.MemberReference, constructor: nodes.DocMemberReference },
|
||||
{ docNodeKind: DocNodeKind.MemberSelector, constructor: nodes.DocMemberSelector },
|
||||
{ docNodeKind: DocNodeKind.MemberSymbol, constructor: nodes.DocMemberSymbol },
|
||||
{ docNodeKind: DocNodeKind.Paragraph, constructor: nodes.DocParagraph },
|
||||
{ docNodeKind: DocNodeKind.ParamBlock, constructor: nodes.DocParamBlock},
|
||||
{ docNodeKind: DocNodeKind.ParamCollection, constructor: nodes.DocParamCollection },
|
||||
{ docNodeKind: DocNodeKind.PlainText, constructor: nodes.DocPlainText },
|
||||
{ docNodeKind: DocNodeKind.Section, constructor: nodes.DocSection },
|
||||
{ docNodeKind: DocNodeKind.SoftBreak, constructor: nodes.DocSoftBreak }
|
||||
{ docNodeKind: DocNodeKind.Block, constructor: nodes.DocBlock },
|
||||
{ docNodeKind: DocNodeKind.BlockTag, constructor: nodes.DocBlockTag },
|
||||
{ docNodeKind: DocNodeKind.CodeSpan, constructor: nodes.DocCodeSpan },
|
||||
{ docNodeKind: DocNodeKind.Comment, constructor: nodes.DocComment },
|
||||
{ docNodeKind: DocNodeKind.DeclarationReference, constructor: nodes.DocDeclarationReference },
|
||||
{ docNodeKind: DocNodeKind.ErrorText, constructor: nodes.DocErrorText },
|
||||
{ docNodeKind: DocNodeKind.EscapedText, constructor: nodes.DocEscapedText },
|
||||
{ docNodeKind: DocNodeKind.Excerpt, constructor: nodes.DocExcerpt },
|
||||
{ docNodeKind: DocNodeKind.FencedCode, constructor: nodes.DocFencedCode },
|
||||
{ docNodeKind: DocNodeKind.HtmlAttribute, constructor: nodes.DocHtmlAttribute },
|
||||
{ docNodeKind: DocNodeKind.HtmlEndTag, constructor: nodes.DocHtmlEndTag },
|
||||
{ docNodeKind: DocNodeKind.HtmlStartTag, constructor: nodes.DocHtmlStartTag },
|
||||
{ docNodeKind: DocNodeKind.InheritDocTag, constructor: nodes.DocInheritDocTag },
|
||||
{ docNodeKind: DocNodeKind.InlineTag, constructor: nodes.DocInlineTag },
|
||||
{ docNodeKind: DocNodeKind.LinkTag, constructor: nodes.DocLinkTag },
|
||||
{ docNodeKind: DocNodeKind.MemberIdentifier, constructor: nodes.DocMemberIdentifier },
|
||||
{ docNodeKind: DocNodeKind.MemberReference, constructor: nodes.DocMemberReference },
|
||||
{ docNodeKind: DocNodeKind.MemberSelector, constructor: nodes.DocMemberSelector },
|
||||
{ docNodeKind: DocNodeKind.MemberSymbol, constructor: nodes.DocMemberSymbol },
|
||||
{ docNodeKind: DocNodeKind.Paragraph, constructor: nodes.DocParagraph },
|
||||
{ docNodeKind: DocNodeKind.ParamBlock, constructor: nodes.DocParamBlock },
|
||||
{ docNodeKind: DocNodeKind.ParamCollection, constructor: nodes.DocParamCollection },
|
||||
{ docNodeKind: DocNodeKind.PlainText, constructor: nodes.DocPlainText },
|
||||
{ docNodeKind: DocNodeKind.Section, constructor: nodes.DocSection },
|
||||
{ docNodeKind: DocNodeKind.SoftBreak, constructor: nodes.DocSoftBreak }
|
||||
]);
|
||||
|
||||
docNodeManager.registerAllowableChildren(DocNodeKind.Section, [
|
||||
|
|
|
@ -69,15 +69,14 @@ export class DocBlockTag extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._tagNameExcerpt
|
||||
];
|
||||
return [this._tagNameExcerpt];
|
||||
}
|
||||
|
||||
public getTokenSequence(): TokenSequence {
|
||||
if (!this._tagNameExcerpt) {
|
||||
throw new Error('DocBlockTag.getTokenSequence() failed because this object did not'
|
||||
+ ' originate from a parsed input');
|
||||
throw new Error(
|
||||
'DocBlockTag.getTokenSequence() failed because this object did not' + ' originate from a parsed input'
|
||||
);
|
||||
}
|
||||
return this._tagNameExcerpt.content;
|
||||
}
|
||||
|
|
|
@ -80,10 +80,6 @@ export class DocCodeSpan extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._openingDelimiterExcerpt,
|
||||
this._codeExcerpt,
|
||||
this._closingDelimiterExcerpt
|
||||
];
|
||||
return [this._openingDelimiterExcerpt, this._codeExcerpt, this._closingDelimiterExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ import { DocParamCollection } from './DocParamCollection';
|
|||
/**
|
||||
* Constructor parameters for {@link DocComment}.
|
||||
*/
|
||||
export interface IDocCommentParameters extends IDocNodeParameters {
|
||||
}
|
||||
export interface IDocCommentParameters extends IDocNodeParameters {}
|
||||
|
||||
/**
|
||||
* Represents an entire documentation comment conforming to the TSDoc structure.
|
||||
|
@ -107,7 +106,7 @@ export class DocComment extends DocNode {
|
|||
|
||||
this.modifierTagSet = new StandardModifierTagSet();
|
||||
|
||||
this._seeBlocks = []
|
||||
this._seeBlocks = [];
|
||||
this._customBlocks = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,9 @@ export class DocDeclarationReference extends DocNode {
|
|||
* Don't call this directly. Instead use {@link TSDocParser}
|
||||
* @internal
|
||||
*/
|
||||
public constructor(parameters: IDocDeclarationReferenceParameters | IDocDeclarationReferenceParsedParameters) {
|
||||
public constructor(
|
||||
parameters: IDocDeclarationReferenceParameters | IDocDeclarationReferenceParsedParameters
|
||||
) {
|
||||
super(parameters);
|
||||
|
||||
if (DocNode.isParsedParameters(parameters)) {
|
||||
|
@ -65,14 +67,14 @@ export class DocDeclarationReference extends DocNode {
|
|||
content: parameters.importPathExcerpt
|
||||
});
|
||||
}
|
||||
if (parameters.importHashExcerpt ) {
|
||||
if (parameters.importHashExcerpt) {
|
||||
this._importHashExcerpt = new DocExcerpt({
|
||||
configuration: this.configuration,
|
||||
excerptKind: ExcerptKind.DeclarationReference_ImportHash,
|
||||
content: parameters.importHashExcerpt
|
||||
});
|
||||
}
|
||||
if (parameters.spacingAfterImportHashExcerpt ) {
|
||||
if (parameters.spacingAfterImportHashExcerpt) {
|
||||
this._spacingAfterImportHashExcerpt = new DocExcerpt({
|
||||
configuration: this.configuration,
|
||||
excerptKind: ExcerptKind.Spacing,
|
||||
|
|
|
@ -57,7 +57,7 @@ export class DocErrorText extends DocNode {
|
|||
if (this._text === undefined) {
|
||||
this._text = this._textExcerpt.content.toString();
|
||||
}
|
||||
return this._text;
|
||||
return this._text;
|
||||
}
|
||||
|
||||
public get textExcerpt(): TokenSequence | undefined {
|
||||
|
@ -97,8 +97,6 @@ export class DocErrorText extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._textExcerpt
|
||||
];
|
||||
return [this._textExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,8 +85,6 @@ export class DocEscapedText extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._encodedTextExcerpt
|
||||
];
|
||||
return [this._encodedTextExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,6 @@ export const enum ExcerptKind {
|
|||
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
||||
|
||||
/**
|
||||
* Constructor parameters for {@link DocExcerpt}.
|
||||
*/
|
||||
|
|
|
@ -99,7 +99,6 @@ export class DocHtmlAttribute extends DocNode {
|
|||
content: parameters.spacingAfterValueExcerpt
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
this._name = parameters.name;
|
||||
this._spacingAfterName = parameters.spacingAfterName;
|
||||
|
|
|
@ -163,7 +163,6 @@ export class DocHtmlStartTag extends DocNode {
|
|||
this._closingDelimiterExcerpt
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Circular reference
|
||||
|
|
|
@ -24,7 +24,6 @@ export interface IDocInheritDocTagParsedParameters extends IDocInlineTagBasePars
|
|||
* Represents an `{@inheritDoc}` tag.
|
||||
*/
|
||||
export class DocInheritDocTag extends DocInlineTagBase {
|
||||
|
||||
private readonly _declarationReference: DocDeclarationReference | undefined;
|
||||
|
||||
/**
|
||||
|
@ -55,9 +54,8 @@ export class DocInheritDocTag extends DocInlineTagBase {
|
|||
}
|
||||
|
||||
/** @override */
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> { // abstract
|
||||
return [
|
||||
this._declarationReference
|
||||
];
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> {
|
||||
// abstract
|
||||
return [this._declarationReference];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ export class DocInlineTag extends DocInlineTagBase {
|
|||
|
||||
if (DocNode.isParsedParameters(parameters)) {
|
||||
if (parameters.tagContentExcerpt) {
|
||||
this._tagContentExcerpt = new DocExcerpt({
|
||||
this._tagContentExcerpt = new DocExcerpt({
|
||||
configuration: this.configuration,
|
||||
excerptKind: ExcerptKind.InlineTag_TagContent,
|
||||
content: parameters.tagContentExcerpt
|
||||
|
@ -78,9 +78,8 @@ export class DocInlineTag extends DocInlineTagBase {
|
|||
}
|
||||
|
||||
/** @override */
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> { // abstract
|
||||
return [
|
||||
this._tagContentExcerpt
|
||||
];
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> {
|
||||
// abstract
|
||||
return [this._tagContentExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,6 @@ export class DocLinkTag extends DocInlineTagBase {
|
|||
this._urlDestination = parameters.urlDestination;
|
||||
this._linkText = parameters.linkText;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @override */
|
||||
|
@ -190,7 +189,8 @@ export class DocLinkTag extends DocInlineTagBase {
|
|||
}
|
||||
|
||||
/** @override */
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> { // abstract
|
||||
protected getChildNodesForContent(): ReadonlyArray<DocNode | undefined> {
|
||||
// abstract
|
||||
return [
|
||||
this._codeDestination,
|
||||
this._urlDestinationExcerpt,
|
||||
|
|
|
@ -113,10 +113,6 @@ export class DocMemberIdentifier extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._leftQuoteExcerpt,
|
||||
this._identifierExcerpt,
|
||||
this._rightQuoteExcerpt
|
||||
];
|
||||
return [this._leftQuoteExcerpt, this._identifierExcerpt, this._rightQuoteExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,16 +112,18 @@ export class DocMemberSelector extends DocNode {
|
|||
if (DocMemberSelector._labelSelectorRegExp.test(this._selector)) {
|
||||
this._selectorKind = SelectorKind.Label;
|
||||
} else {
|
||||
this._errorMessage = 'A label selector must be comprised of upper case letters, numbers,'
|
||||
+ ' and underscores and must not start with a number';
|
||||
this._errorMessage =
|
||||
'A label selector must be comprised of upper case letters, numbers,' +
|
||||
' and underscores and must not start with a number';
|
||||
}
|
||||
} else {
|
||||
if (StringChecks.isSystemSelector(this._selector)) {
|
||||
this._selectorKind = SelectorKind.System;
|
||||
} else if (DocMemberSelector._likeSystemSelectorRegExp.test(this._selector)) {
|
||||
// It looks like a system selector, but is not
|
||||
this._errorMessage = `The selector ${JSON.stringify(this._selector)}`
|
||||
+ ` is not a recognized TSDoc system selector name`;
|
||||
this._errorMessage =
|
||||
`The selector ${JSON.stringify(this._selector)}` +
|
||||
` is not a recognized TSDoc system selector name`;
|
||||
} else {
|
||||
// It doesn't look like anything we recognize
|
||||
this._errorMessage = 'Invalid syntax for selector';
|
||||
|
@ -163,8 +165,6 @@ export class DocMemberSelector extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._selectorExcerpt
|
||||
];
|
||||
return [this._selectorExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,31 +9,31 @@ import { TSDocConfiguration } from '../configuration/TSDocConfiguration';
|
|||
* NPM package name, followed by a "#" symbol, followed by the class name (without the "Doc" prefix).
|
||||
*/
|
||||
export const enum DocNodeKind {
|
||||
Block = 'Block',
|
||||
BlockTag = 'BlockTag',
|
||||
Excerpt = 'Excerpt',
|
||||
FencedCode = 'FencedCode',
|
||||
CodeSpan = 'CodeSpan',
|
||||
Comment = 'Comment',
|
||||
DeclarationReference = 'DeclarationReference',
|
||||
ErrorText = 'ErrorText',
|
||||
EscapedText = 'EscapedText',
|
||||
HtmlAttribute = 'HtmlAttribute',
|
||||
HtmlEndTag = 'HtmlEndTag',
|
||||
HtmlStartTag = 'HtmlStartTag',
|
||||
InheritDocTag = 'InheritDocTag',
|
||||
InlineTag = 'InlineTag',
|
||||
LinkTag = 'LinkTag',
|
||||
MemberIdentifier = 'MemberIdentifier',
|
||||
MemberReference = 'MemberReference',
|
||||
MemberSelector = 'MemberSelector',
|
||||
MemberSymbol = 'MemberSymbol',
|
||||
Paragraph = 'Paragraph',
|
||||
ParamBlock = 'ParamBlock',
|
||||
ParamCollection = 'ParamCollection',
|
||||
PlainText = 'PlainText',
|
||||
Section = 'Section',
|
||||
SoftBreak = 'SoftBreak'
|
||||
Block = 'Block',
|
||||
BlockTag = 'BlockTag',
|
||||
Excerpt = 'Excerpt',
|
||||
FencedCode = 'FencedCode',
|
||||
CodeSpan = 'CodeSpan',
|
||||
Comment = 'Comment',
|
||||
DeclarationReference = 'DeclarationReference',
|
||||
ErrorText = 'ErrorText',
|
||||
EscapedText = 'EscapedText',
|
||||
HtmlAttribute = 'HtmlAttribute',
|
||||
HtmlEndTag = 'HtmlEndTag',
|
||||
HtmlStartTag = 'HtmlStartTag',
|
||||
InheritDocTag = 'InheritDocTag',
|
||||
InlineTag = 'InlineTag',
|
||||
LinkTag = 'LinkTag',
|
||||
MemberIdentifier = 'MemberIdentifier',
|
||||
MemberReference = 'MemberReference',
|
||||
MemberSelector = 'MemberSelector',
|
||||
MemberSymbol = 'MemberSymbol',
|
||||
Paragraph = 'Paragraph',
|
||||
ParamBlock = 'ParamBlock',
|
||||
ParamCollection = 'ParamCollection',
|
||||
PlainText = 'PlainText',
|
||||
Section = 'Section',
|
||||
SoftBreak = 'SoftBreak'
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +93,7 @@ export abstract class DocNode {
|
|||
// Do this sanity check here, since the constructor cannot access abstract members
|
||||
this.configuration.docNodeManager.throwIfNotRegisteredKind(this.kind);
|
||||
|
||||
return this.onGetChildNodes().filter(x => x !== undefined) as ReadonlyArray<DocNode>;
|
||||
return this.onGetChildNodes().filter((x) => x !== undefined) as ReadonlyArray<DocNode>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,9 +113,9 @@ export abstract class DocNode {
|
|||
* hierarchy for its constructor parameters. The "parser scenario" constructs the object by parsing a TypeScript
|
||||
* source file, does create DocExcerpt child nodes, and generally uses the {@link IDocNodeParsedParameters} hierarchy.
|
||||
*/
|
||||
public static isParsedParameters(parameters: IDocNodeParameters | IDocNodeParsedParameters):
|
||||
parameters is IDocNodeParsedParameters {
|
||||
|
||||
public static isParsedParameters(
|
||||
parameters: IDocNodeParameters | IDocNodeParsedParameters
|
||||
): parameters is IDocNodeParsedParameters {
|
||||
return (parameters as IDocNodeParsedParameters).parsed === true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,12 @@ import { DocNode, IDocNodeParameters, IDocNodeParsedParameters } from './DocNode
|
|||
/**
|
||||
* Constructor parameters for {@link DocNodeContainer}.
|
||||
*/
|
||||
export interface IDocNodeContainerParameters extends IDocNodeParameters {
|
||||
|
||||
}
|
||||
export interface IDocNodeContainerParameters extends IDocNodeParameters {}
|
||||
|
||||
/**
|
||||
* Constructor parameters for {@link DocNodeContainer}.
|
||||
*/
|
||||
export interface IDocNodeContainerParsedParameters extends IDocNodeParsedParameters {
|
||||
|
||||
}
|
||||
export interface IDocNodeContainerParsedParameters extends IDocNodeParsedParameters {}
|
||||
|
||||
/**
|
||||
* DocNodeContainer is the base class for DocNode classes that allow arbitrary child nodes to be added by the consumer.
|
||||
|
@ -25,9 +21,10 @@ export abstract class DocNodeContainer extends DocNode {
|
|||
* Don't call this directly. Instead use {@link TSDocParser}
|
||||
* @internal
|
||||
*/
|
||||
public constructor(parameters: IDocNodeContainerParameters | IDocNodeContainerParsedParameters,
|
||||
childNodes?: ReadonlyArray<DocNode>) {
|
||||
|
||||
public constructor(
|
||||
parameters: IDocNodeContainerParameters | IDocNodeContainerParsedParameters,
|
||||
childNodes?: ReadonlyArray<DocNode>
|
||||
) {
|
||||
super(parameters);
|
||||
|
||||
if (childNodes !== undefined && childNodes.length > 0) {
|
||||
|
@ -47,8 +44,10 @@ export abstract class DocNodeContainer extends DocNode {
|
|||
*/
|
||||
public appendNode(docNode: DocNode): void {
|
||||
if (!this.configuration.docNodeManager.isAllowedChild(this.kind, docNode.kind)) {
|
||||
throw new Error(`The TSDocConfiguration does not allow a ${this.kind} node to`
|
||||
+ ` contain a node of type ${docNode.kind}`);
|
||||
throw new Error(
|
||||
`The TSDocConfiguration does not allow a ${this.kind} node to` +
|
||||
` contain a node of type ${docNode.kind}`
|
||||
);
|
||||
}
|
||||
|
||||
this._nodes!.push(docNode);
|
||||
|
|
|
@ -4,8 +4,7 @@ import { DocNodeContainer, IDocNodeContainerParameters } from './DocNodeContaine
|
|||
/**
|
||||
* Constructor parameters for {@link DocParagraph}.
|
||||
*/
|
||||
export interface IDocParagraphParameters extends IDocNodeContainerParameters {
|
||||
}
|
||||
export interface IDocParagraphParameters extends IDocNodeContainerParameters {}
|
||||
|
||||
/**
|
||||
* Represents a paragraph of text, similar to a `<p>` element in HTML.
|
||||
|
|
|
@ -146,7 +146,6 @@ export class DocParamBlock extends DocBlock {
|
|||
content: parameters.unsupportedJsdocTypeAfterHyphenExcerpt
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,7 @@ import { DocParamBlock } from './DocParamBlock';
|
|||
/**
|
||||
* Constructor parameters for {@link DocParamCollection}.
|
||||
*/
|
||||
export interface IDocParamCollectionParameters extends IDocNodeParameters {
|
||||
|
||||
}
|
||||
export interface IDocParamCollectionParameters extends IDocNodeParameters {}
|
||||
|
||||
/**
|
||||
* Represents a collection of DocParamBlock objects and provides efficient operations for looking up the
|
||||
|
|
|
@ -80,8 +80,6 @@ export class DocPlainText extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._textExcerpt
|
||||
];
|
||||
return [this._textExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,12 @@ import {
|
|||
/**
|
||||
* Constructor parameters for {@link DocSection}.
|
||||
*/
|
||||
export interface IDocSectionParameters extends IDocNodeContainerParameters {
|
||||
|
||||
}
|
||||
export interface IDocSectionParameters extends IDocNodeContainerParameters {}
|
||||
|
||||
/**
|
||||
* Constructor parameters for {@link DocSection}.
|
||||
*/
|
||||
export interface IDocSectionParsedParameters extends IDocNodeContainerParsedParameters {
|
||||
|
||||
}
|
||||
export interface IDocSectionParsedParameters extends IDocNodeContainerParsedParameters {}
|
||||
|
||||
/**
|
||||
* Represents a general block of rich text.
|
||||
|
@ -28,9 +24,10 @@ export class DocSection extends DocNodeContainer {
|
|||
* Don't call this directly. Instead use {@link TSDocParser}
|
||||
* @internal
|
||||
*/
|
||||
public constructor(parameters: IDocSectionParameters | IDocSectionParsedParameters,
|
||||
childNodes?: ReadonlyArray<DocNode>) {
|
||||
|
||||
public constructor(
|
||||
parameters: IDocSectionParameters | IDocSectionParsedParameters,
|
||||
childNodes?: ReadonlyArray<DocNode>
|
||||
) {
|
||||
super(parameters, childNodes);
|
||||
}
|
||||
|
||||
|
@ -65,5 +62,4 @@ export class DocSection extends DocNodeContainer {
|
|||
this.appendNodeInParagraph(docNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ import { DocExcerpt, ExcerptKind } from './DocExcerpt';
|
|||
/**
|
||||
* Constructor parameters for {@link DocSoftBreak}.
|
||||
*/
|
||||
export interface IDocSoftBreakParameters extends IDocNodeParameters {
|
||||
}
|
||||
export interface IDocSoftBreakParameters extends IDocNodeParameters {}
|
||||
|
||||
/**
|
||||
* Constructor parameters for {@link DocSoftBreak}.
|
||||
|
@ -54,8 +53,6 @@ export class DocSoftBreak extends DocNode {
|
|||
|
||||
/** @override */
|
||||
protected onGetChildNodes(): ReadonlyArray<DocNode | undefined> {
|
||||
return [
|
||||
this._softBreakExcerpt
|
||||
];
|
||||
return [this._softBreakExcerpt];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
export * from './DocBlock';
|
||||
export * from './DocBlockTag';
|
||||
export * from './DocCodeSpan';
|
||||
|
|
|
@ -53,12 +53,16 @@ export class LineExtractor {
|
|||
case State.BeginComment2:
|
||||
parserContext.log.addMessageForTextRange(
|
||||
TSDocMessageId.CommentNotFound,
|
||||
'Expecting a "/**" comment', range);
|
||||
'Expecting a "/**" comment',
|
||||
range
|
||||
);
|
||||
return false;
|
||||
default:
|
||||
parserContext.log.addMessageForTextRange(
|
||||
TSDocMessageId.CommentMissingClosingDelimiter,
|
||||
'Unexpected end of input', range);
|
||||
'Unexpected end of input',
|
||||
range
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +82,8 @@ export class LineExtractor {
|
|||
parserContext.log.addMessageForTextRange(
|
||||
TSDocMessageId.CommentOpeningDelimiterSyntax,
|
||||
'Expecting a leading "/**"',
|
||||
range.getNewRange(currentIndex, currentIndex + 1));
|
||||
range.getNewRange(currentIndex, currentIndex + 1)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -94,7 +99,8 @@ export class LineExtractor {
|
|||
parserContext.log.addMessageForTextRange(
|
||||
TSDocMessageId.CommentOpeningDelimiterSyntax,
|
||||
'Expecting a leading "/**"',
|
||||
range.getNewRange(currentIndex, currentIndex + 1));
|
||||
range.getNewRange(currentIndex, currentIndex + 1)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
DocSection,
|
||||
DocNode,
|
||||
DocNodeKind,
|
||||
DocParagraph,
|
||||
DocPlainText
|
||||
} from '../nodes';
|
||||
import { DocSection, DocNode, DocNodeKind, DocParagraph, DocPlainText } from '../nodes';
|
||||
|
||||
/**
|
||||
* The ParagraphSplitter is a secondary stage that runs after the NodeParser has constructed
|
||||
|
@ -68,7 +62,6 @@ export class ParagraphSplitter {
|
|||
|
||||
let currentIndex: number = 0;
|
||||
while (currentIndex < inputParagraphNodes.length) {
|
||||
|
||||
// Scan forwards to the end of the line
|
||||
let isBlankLine: boolean = true;
|
||||
let lineEndIndex: number = currentIndex; // non-inclusive
|
||||
|
|
|
@ -29,25 +29,33 @@ export class ParserMessageLog {
|
|||
* Append a message associated with a TextRange.
|
||||
*/
|
||||
public addMessageForTextRange(messageId: TSDocMessageId, messageText: string, textRange: TextRange): void {
|
||||
this.addMessage(new ParserMessage({
|
||||
messageId,
|
||||
messageText,
|
||||
textRange
|
||||
}));
|
||||
this.addMessage(
|
||||
new ParserMessage({
|
||||
messageId,
|
||||
messageText,
|
||||
textRange
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a message associated with a TokenSequence.
|
||||
*/
|
||||
public addMessageForTokenSequence(messageId: TSDocMessageId, messageText: string, tokenSequence: TokenSequence,
|
||||
docNode?: DocNode): void {
|
||||
this.addMessage(new ParserMessage({
|
||||
messageId,
|
||||
messageText,
|
||||
textRange: tokenSequence.getContainingTextRange(),
|
||||
tokenSequence,
|
||||
docNode
|
||||
}));
|
||||
public addMessageForTokenSequence(
|
||||
messageId: TSDocMessageId,
|
||||
messageText: string,
|
||||
tokenSequence: TokenSequence,
|
||||
docNode?: DocNode
|
||||
): void {
|
||||
this.addMessage(
|
||||
new ParserMessage({
|
||||
messageId,
|
||||
messageText,
|
||||
textRange: tokenSequence.getContainingTextRange(),
|
||||
tokenSequence,
|
||||
docNode
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,12 +73,14 @@ export class ParserMessageLog {
|
|||
tokenSequence = docErrorText.errorLocation;
|
||||
}
|
||||
|
||||
this.addMessage(new ParserMessage({
|
||||
messageId: docErrorText.messageId,
|
||||
messageText: docErrorText.errorMessage,
|
||||
textRange: tokenSequence.getContainingTextRange(),
|
||||
tokenSequence: tokenSequence,
|
||||
docNode: docErrorText
|
||||
}));
|
||||
this.addMessage(
|
||||
new ParserMessage({
|
||||
messageId: docErrorText.messageId,
|
||||
messageText: docErrorText.errorMessage,
|
||||
textRange: tokenSequence.getContainingTextRange(),
|
||||
tokenSequence: tokenSequence,
|
||||
docNode: docErrorText
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,10 +32,18 @@ export class StringChecks {
|
|||
|
||||
private static readonly _systemSelectors: Set<string> = new Set<string>([
|
||||
// For classes:
|
||||
'instance', 'static', 'constructor',
|
||||
'instance',
|
||||
'static',
|
||||
'constructor',
|
||||
|
||||
// For merged declarations:
|
||||
'class', 'enum', 'function', 'interface', 'namespace', 'type', 'variable'
|
||||
'class',
|
||||
'enum',
|
||||
'function',
|
||||
'interface',
|
||||
'namespace',
|
||||
'type',
|
||||
'variable'
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -76,8 +84,10 @@ export class StringChecks {
|
|||
return 'The URL cannot be empty';
|
||||
}
|
||||
if (!StringChecks._urlSchemeRegExp.test(url)) {
|
||||
return 'An @link URL must begin with a scheme comprised only of letters and numbers followed by "://".'
|
||||
+ ' (For general URLs, use an HTML "<a>" tag instead.)';
|
||||
return (
|
||||
'An @link URL must begin with a scheme comprised only of letters and numbers followed by "://".' +
|
||||
' (For general URLs, use an HTML "<a>" tag instead.)'
|
||||
);
|
||||
}
|
||||
if (!StringChecks._urlSchemeAfterRegExp.test(url)) {
|
||||
return 'An @link URL must have at least one character after "://"';
|
||||
|
@ -125,7 +135,10 @@ export class StringChecks {
|
|||
/**
|
||||
* Tests whether the input string is a valid declaration reference import path.
|
||||
*/
|
||||
public static explainIfInvalidImportPath(importPath: string, prefixedByPackageName: boolean): string | undefined {
|
||||
public static explainIfInvalidImportPath(
|
||||
importPath: string,
|
||||
prefixedByPackageName: boolean
|
||||
): string | undefined {
|
||||
if (importPath.length > 0) {
|
||||
if (importPath.indexOf('//') >= 0) {
|
||||
return 'An import path must not contain "//"';
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/**
|
||||
* Unique identifiers for messages reported by the TSDoc parser.
|
||||
*
|
||||
|
|
|
@ -100,11 +100,13 @@ export class TextRange {
|
|||
* then the output would be "12[345]67".
|
||||
*/
|
||||
public getDebugDump(posDelimiter: string, endDelimiter: string): string {
|
||||
return this.buffer.substring(0, this.pos)
|
||||
+ posDelimiter
|
||||
+ this.buffer.substring(this.pos, this.end)
|
||||
+ endDelimiter
|
||||
+ this.buffer.substring(this.end);
|
||||
return (
|
||||
this.buffer.substring(0, this.pos) +
|
||||
posDelimiter +
|
||||
this.buffer.substring(this.pos, this.end) +
|
||||
endDelimiter +
|
||||
this.buffer.substring(this.end)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,12 +134,14 @@ export class TextRange {
|
|||
const current: string = this.buffer[currentIndex];
|
||||
++currentIndex;
|
||||
|
||||
if (current === '\r') { // CR
|
||||
if (current === '\r') {
|
||||
// CR
|
||||
// Ignore '\r' and assume it will always have an accompanying '\n'
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '\n') { // LF
|
||||
if (current === '\n') {
|
||||
// LF
|
||||
++line;
|
||||
column = 1;
|
||||
} else {
|
||||
|
|
|
@ -54,8 +54,10 @@ export class TokenReader {
|
|||
public extractAccumulatedSequence(): TokenSequence {
|
||||
if (this._accumulatedStartIndex === this._currentIndex) {
|
||||
// If this happens, it indicates a parser bug:
|
||||
throw new Error('Parser assertion failed: The queue should not be empty when'
|
||||
+ ' extractAccumulatedSequence() is called');
|
||||
throw new Error(
|
||||
'Parser assertion failed: The queue should not be empty when' +
|
||||
' extractAccumulatedSequence() is called'
|
||||
);
|
||||
}
|
||||
|
||||
const sequence: TokenSequence = new TokenSequence({
|
||||
|
@ -102,9 +104,11 @@ export class TokenReader {
|
|||
startIndex: this._accumulatedStartIndex,
|
||||
endIndex: this._currentIndex
|
||||
});
|
||||
const tokenStrings: string[] = sequence.tokens.map(x => x.toString());
|
||||
throw new Error('Parser assertion failed: The queue should be empty, but it contains:\n'
|
||||
+ JSON.stringify(tokenStrings));
|
||||
const tokenStrings: string[] = sequence.tokens.map((x) => x.toString());
|
||||
throw new Error(
|
||||
'Parser assertion failed: The queue should be empty, but it contains:\n' +
|
||||
JSON.stringify(tokenStrings)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ export class TokenSequence {
|
|||
* Returns the concatenated text of all the tokens.
|
||||
*/
|
||||
public toString(): string {
|
||||
return this.tokens.map(x => x.toString()).join('');
|
||||
return this.tokens.map((x) => x.toString()).join('');
|
||||
}
|
||||
|
||||
private _validateBounds(): void {
|
||||
|
|
|
@ -2,10 +2,9 @@ import { TextRange } from './TextRange';
|
|||
import { Token, TokenKind } from './Token';
|
||||
|
||||
export class Tokenizer {
|
||||
private static readonly _commonMarkPunctuationCharacters: string
|
||||
= '!"#$%&\'()*+,\-.\/:;<=>?@[\\]^`{|}~';
|
||||
private static readonly _wordCharacters: string
|
||||
= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
|
||||
private static readonly _commonMarkPunctuationCharacters: string = '!"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~';
|
||||
private static readonly _wordCharacters: string =
|
||||
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_';
|
||||
|
||||
private static _charCodeMap: { [charCode: number]: TokenKind | undefined };
|
||||
private static _punctuationTokens: { [tokenKind: number]: boolean };
|
||||
|
@ -27,13 +26,11 @@ export class Tokenizer {
|
|||
}
|
||||
|
||||
if (lastLine) {
|
||||
tokens.push(new Token(TokenKind.EndOfInput,
|
||||
lastLine.getNewRange(lastLine.end, lastLine.end),
|
||||
lastLine));
|
||||
tokens.push(
|
||||
new Token(TokenKind.EndOfInput, lastLine.getNewRange(lastLine.end, lastLine.end), lastLine)
|
||||
);
|
||||
} else {
|
||||
tokens.push(new Token(TokenKind.EndOfInput,
|
||||
TextRange.empty,
|
||||
TextRange.empty));
|
||||
tokens.push(new Token(TokenKind.EndOfInput, TextRange.empty, TextRange.empty));
|
||||
}
|
||||
|
||||
return tokens;
|
||||
|
@ -68,9 +65,11 @@ export class Tokenizer {
|
|||
// 1. There is an existing token, AND
|
||||
// 2. It is the same kind of token, AND
|
||||
// 3. It's not punctuation (which is always one character)
|
||||
if (tokenKind !== undefined
|
||||
&& characterKind === tokenKind
|
||||
&& Tokenizer._isMultiCharacterToken(tokenKind)) {
|
||||
if (
|
||||
tokenKind !== undefined &&
|
||||
characterKind === tokenKind &&
|
||||
Tokenizer._isMultiCharacterToken(tokenKind)
|
||||
) {
|
||||
// yes, append
|
||||
} else {
|
||||
// Is there a previous completed token to push?
|
||||
|
@ -125,29 +124,29 @@ export class Tokenizer {
|
|||
|
||||
// !"#$%&\'()*+,\-.\/:;<=>?@[\\]^_`{|}~
|
||||
const specialMap: { [character: string]: TokenKind } = {
|
||||
'\\' : TokenKind.Backslash,
|
||||
'<' : TokenKind.LessThan,
|
||||
'>' : TokenKind.GreaterThan,
|
||||
'=' : TokenKind.Equals,
|
||||
'\'' : TokenKind.SingleQuote,
|
||||
'"' : TokenKind.DoubleQuote,
|
||||
'/' : TokenKind.Slash,
|
||||
'-' : TokenKind.Hyphen,
|
||||
'@' : TokenKind.AtSign,
|
||||
'{' : TokenKind.LeftCurlyBracket,
|
||||
'}' : TokenKind.RightCurlyBracket,
|
||||
'`' : TokenKind.Backtick,
|
||||
'.' : TokenKind.Period,
|
||||
':' : TokenKind.Colon,
|
||||
',' : TokenKind.Comma,
|
||||
'[' : TokenKind.LeftSquareBracket,
|
||||
']' : TokenKind.RightSquareBracket,
|
||||
'|' : TokenKind.Pipe,
|
||||
'(' : TokenKind.LeftParenthesis,
|
||||
')' : TokenKind.RightParenthesis,
|
||||
'#' : TokenKind.PoundSymbol,
|
||||
'+' : TokenKind.Plus,
|
||||
'$' : TokenKind.DollarSign
|
||||
'\\': TokenKind.Backslash,
|
||||
'<': TokenKind.LessThan,
|
||||
'>': TokenKind.GreaterThan,
|
||||
'=': TokenKind.Equals,
|
||||
"'": TokenKind.SingleQuote,
|
||||
'"': TokenKind.DoubleQuote,
|
||||
'/': TokenKind.Slash,
|
||||
'-': TokenKind.Hyphen,
|
||||
'@': TokenKind.AtSign,
|
||||
'{': TokenKind.LeftCurlyBracket,
|
||||
'}': TokenKind.RightCurlyBracket,
|
||||
'`': TokenKind.Backtick,
|
||||
'.': TokenKind.Period,
|
||||
':': TokenKind.Colon,
|
||||
',': TokenKind.Comma,
|
||||
'[': TokenKind.LeftSquareBracket,
|
||||
']': TokenKind.RightSquareBracket,
|
||||
'|': TokenKind.Pipe,
|
||||
'(': TokenKind.LeftParenthesis,
|
||||
')': TokenKind.RightParenthesis,
|
||||
'#': TokenKind.PoundSymbol,
|
||||
'+': TokenKind.Plus,
|
||||
$: TokenKind.DollarSign
|
||||
};
|
||||
for (const key of Object.getOwnPropertyNames(specialMap)) {
|
||||
Tokenizer._charCodeMap[key.charCodeAt(0)] = specialMap[key];
|
||||
|
|
|
@ -8,36 +8,39 @@ function parseAndMatchSnapshot(buffer: string): void {
|
|||
expect({
|
||||
buffer: TestHelpers.getEscaped(buffer),
|
||||
comment: TestHelpers.getEscaped(parserContext.commentRange.toString()),
|
||||
lines: parserContext.lines.map(line => TestHelpers.getEscaped(line.toString())),
|
||||
logMessages: parserContext.log.messages.map(message => message.text)
|
||||
lines: parserContext.lines.map((line) => TestHelpers.getEscaped(line.toString())),
|
||||
logMessages: parserContext.log.messages.map((message) => message.text)
|
||||
}).toMatchSnapshot();
|
||||
}
|
||||
|
||||
test('A. Whitespace variations', () => {
|
||||
parseAndMatchSnapshot(`/***/`); // 1
|
||||
parseAndMatchSnapshot(` /***/ `); // 2
|
||||
parseAndMatchSnapshot(` /** */ `); // 3
|
||||
parseAndMatchSnapshot(` /**\n\n*/ `); // 4
|
||||
parseAndMatchSnapshot(` /**L1*/ `); // 5
|
||||
parseAndMatchSnapshot(` /** L1 */ `); // 6
|
||||
parseAndMatchSnapshot(` /**L1\n*/ `); // 7
|
||||
parseAndMatchSnapshot(` /**L1*\n*/ `); // 8
|
||||
parseAndMatchSnapshot(` /**\nL1*/ `); // 9
|
||||
parseAndMatchSnapshot(` /**\n L1 */ `); // 10
|
||||
parseAndMatchSnapshot(` /**\nL1\n*/ `); // 11
|
||||
parseAndMatchSnapshot(` /**\nL1\n\nL2*/ `); // 12
|
||||
parseAndMatchSnapshot(` /**\n*L1\n*/ `); // 13
|
||||
parseAndMatchSnapshot(` /**\n * L1\n*/ `); // 14
|
||||
parseAndMatchSnapshot(` /**\n * L1\n */ `); // 15
|
||||
parseAndMatchSnapshot(` /**L1\n *L2\nL3*/ `); // 16
|
||||
parseAndMatchSnapshot(` /** L1\n * L2\n L3*/ `); // 17
|
||||
parseAndMatchSnapshot(` /** L1 \n * L2 \n L3 */ `); // 18
|
||||
parseAndMatchSnapshot([ // 19
|
||||
'/** L1 ',
|
||||
' * L2 ',
|
||||
' L3 ',
|
||||
' L4 */'
|
||||
].join('\r\n'));
|
||||
parseAndMatchSnapshot(`/***/`); // 1
|
||||
parseAndMatchSnapshot(` /***/ `); // 2
|
||||
parseAndMatchSnapshot(` /** */ `); // 3
|
||||
parseAndMatchSnapshot(` /**\n\n*/ `); // 4
|
||||
parseAndMatchSnapshot(` /**L1*/ `); // 5
|
||||
parseAndMatchSnapshot(` /** L1 */ `); // 6
|
||||
parseAndMatchSnapshot(` /**L1\n*/ `); // 7
|
||||
parseAndMatchSnapshot(` /**L1*\n*/ `); // 8
|
||||
parseAndMatchSnapshot(` /**\nL1*/ `); // 9
|
||||
parseAndMatchSnapshot(` /**\n L1 */ `); // 10
|
||||
parseAndMatchSnapshot(` /**\nL1\n*/ `); // 11
|
||||
parseAndMatchSnapshot(` /**\nL1\n\nL2*/ `); // 12
|
||||
parseAndMatchSnapshot(` /**\n*L1\n*/ `); // 13
|
||||
parseAndMatchSnapshot(` /**\n * L1\n*/ `); // 14
|
||||
parseAndMatchSnapshot(` /**\n * L1\n */ `); // 15
|
||||
parseAndMatchSnapshot(` /**L1\n *L2\nL3*/ `); // 16
|
||||
parseAndMatchSnapshot(` /** L1\n * L2\n L3*/ `); // 17
|
||||
parseAndMatchSnapshot(` /** L1 \n * L2 \n L3 */ `); // 18
|
||||
parseAndMatchSnapshot(
|
||||
[
|
||||
// 19
|
||||
'/** L1 ',
|
||||
' * L2 ',
|
||||
' L3 ',
|
||||
' L4 */'
|
||||
].join('\r\n')
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: Special handling for these somewhat common ornamentations
|
||||
|
@ -52,43 +55,14 @@ test('B. Extra stars', () => {
|
|||
});
|
||||
|
||||
test('C. Missing stars', () => {
|
||||
parseAndMatchSnapshot([
|
||||
'/**',
|
||||
'```',
|
||||
'a',
|
||||
' b',
|
||||
' c ',
|
||||
' d',
|
||||
'```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
parseAndMatchSnapshot(['/**', '```', 'a', ' b', ' c ', ' d', '```', ' */'].join('\n'));
|
||||
|
||||
parseAndMatchSnapshot([
|
||||
'/**',
|
||||
'```',
|
||||
'ee',
|
||||
' ff',
|
||||
' gg ',
|
||||
' hh',
|
||||
'```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
parseAndMatchSnapshot(['/**', '```', 'ee', ' ff', ' gg ', ' hh', '```', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('D. Newline styles', () => {
|
||||
parseAndMatchSnapshot([
|
||||
'',
|
||||
'/**',
|
||||
' * L1',
|
||||
' */',
|
||||
''
|
||||
].join('\r\n'));
|
||||
parseAndMatchSnapshot([
|
||||
'/**',
|
||||
'L1',
|
||||
'L2',
|
||||
'*/'
|
||||
].join('\r\n'));
|
||||
parseAndMatchSnapshot(['', '/**', ' * L1', ' */', ''].join('\r\n'));
|
||||
parseAndMatchSnapshot(['/**', 'L1', 'L2', '*/'].join('\r\n'));
|
||||
|
||||
// We currently don't support CR or LFCR, so a single "\r" is treated
|
||||
// as part of the line.
|
||||
|
|
|
@ -1,44 +1,30 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('00 Tokenizer simple case', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * line 1 ', // extra space at end of line
|
||||
' * line 2',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * line 1 ', // extra space at end of line
|
||||
' * line 2',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('01 Tokenizer degenerate cases', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot('/***/');
|
||||
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' *',
|
||||
' */'
|
||||
].join('\n'));
|
||||
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' ',
|
||||
' ',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' *', ' */'].join('\n'));
|
||||
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' ', ' ', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('02 Backslash escapes: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * \\$\\@param',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * \\$\\@param', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('03 Backslash escapes: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * letter: \\A space: \\ end of line: \\',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * letter: \\A space: \\ end of line: \\', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,95 +1,64 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('00 Code span basic, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * line `1`',
|
||||
' * line ` 2` sdf',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * M`&`M',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * line `1`', ' * line ` 2` sdf', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * M`&`M', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('01 Code span basic, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * `multi',
|
||||
' * line`',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * ``',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * `multi', ' * line`', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * ``', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('03 Code fence, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * This is a code fence with all parts:',
|
||||
' * ```a language! ',
|
||||
' * some `code` here',
|
||||
' * ``` ',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * This is a code fence with no language or trailing whitespace:',
|
||||
' * ```',
|
||||
' * some `code` here',
|
||||
' * ```*/'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * This is a code fence with all parts:',
|
||||
' * ```a language! ',
|
||||
' * some `code` here',
|
||||
' * ``` ',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * This is a code fence with no language or trailing whitespace:',
|
||||
' * ```',
|
||||
' * some `code` here',
|
||||
' * ```*/'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 Code fence, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Code fence incorrectly indented:',
|
||||
' * ```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Code fence not starting the line:',
|
||||
' *a```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Code fence not being terminated 1:',
|
||||
' * ```*/'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Code fence not being terminated 2:',
|
||||
' * ``` some stuff',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Language having backticks:',
|
||||
' * ``` some stuff ```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Closing delimiter being indented:',
|
||||
' * ```',
|
||||
' * code',
|
||||
' * ```',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * Closing delimiter not being on a line by itself:',
|
||||
' * ```',
|
||||
' * code',
|
||||
' * ``` a',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Code fence incorrectly indented:', ' * ```', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Code fence not starting the line:', ' *a```', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Code fence not being terminated 1:', ' * ```*/'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Code fence not being terminated 2:', ' * ``` some stuff', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Language having backticks:', ' * ``` some stuff ```', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * Closing delimiter being indented:', ' * ```', ' * code', ' * ```', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * Closing delimiter not being on a line by itself:',
|
||||
' * ```',
|
||||
' * code',
|
||||
' * ``` a',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,129 +1,101 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('01 HTML start tags: simple, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag/>',
|
||||
' * <tag-a />',
|
||||
' * <tag-b ><tag-c />',
|
||||
' * <tag-d',
|
||||
' * >',
|
||||
' * <tag-e',
|
||||
' * /> ',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * <tag/>',
|
||||
' * <tag-a />',
|
||||
' * <tag-b ><tag-c />',
|
||||
' * <tag-d',
|
||||
' * >',
|
||||
' * <tag-e',
|
||||
' * /> ',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('02 HTML start tags: simple, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * < tag/>',
|
||||
' * <tag -a />',
|
||||
' * <tag-b /<tag-c / >',
|
||||
' * <tag-d',
|
||||
' */'
|
||||
].join('\n'));
|
||||
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * < tag/>', ' * <tag -a />', ' * <tag-b /<tag-c / >', ' * <tag-d', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('03 HTML start tags: with attributes, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag-a attr-one="one" >',
|
||||
' * <tag-b',
|
||||
' * attr-two',
|
||||
' * = "2"',
|
||||
' * />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag-c attr-three="3" four=\'4\'/>',
|
||||
' * <tag-d',
|
||||
' * attr-five',
|
||||
' * = "5"',
|
||||
' * six',
|
||||
' * = \'6\'',
|
||||
' * />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag-e attr-one="one" two=\'two\'/>',
|
||||
' * <tag-f',
|
||||
' * attr-one',
|
||||
' * = "one"',
|
||||
' * two',
|
||||
' * = \'two\'',
|
||||
' * />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * <tag-a attr-one="one" >', ' * <tag-b', ' * attr-two', ' * = "2"', ' * />', ' */'].join(
|
||||
'\n'
|
||||
)
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * <tag-c attr-three="3" four=\'4\'/>',
|
||||
' * <tag-d',
|
||||
' * attr-five',
|
||||
' * = "5"',
|
||||
' * six',
|
||||
" * = '6'",
|
||||
' * />',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * <tag-e attr-one="one" two=\'two\'/>',
|
||||
' * <tag-f',
|
||||
' * attr-one',
|
||||
' * = "one"',
|
||||
' * two',
|
||||
" * = 'two'",
|
||||
' * />',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 HTML start tags: with attributes, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag-a attr -one="one" />',
|
||||
' * <tag-b attr- two="two" />',
|
||||
' * <tag-c attr-three=\'three" />',
|
||||
' * <tag-d attr-four=@"four" />',
|
||||
' * <tag-e attr-five@="five" />',
|
||||
' * <tag-f attr-six="six"seven="seven" />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag-g attr="multi',
|
||||
' * line" />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * <tag-a attr -one="one" />',
|
||||
' * <tag-b attr- two="two" />',
|
||||
' * <tag-c attr-three=\'three" />',
|
||||
' * <tag-d attr-four=@"four" />',
|
||||
' * <tag-e attr-five@="five" />',
|
||||
' * <tag-f attr-six="six"seven="seven" />',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * <tag-g attr="multi', ' * line" />', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('05 Eclipsed TSDoc', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <tag attr-one="@tag" />',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * <tag attr-one="@tag" />', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('06 Closing tags, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * </tag-a>',
|
||||
' * </tag-b >',
|
||||
' * </tag-c',
|
||||
' * >',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * </tag-a>', ' * </tag-b >', ' * </tag-c', ' * >', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('07 Closing tags, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * </tag-a/>',
|
||||
' * </ tag-b>',
|
||||
' * </tag-c',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * </tag-a/>', ' * </ tag-b>', ' * </tag-c', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('08 Unusual HTML names, positive', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <a1/>',
|
||||
' * <a-a>',
|
||||
' * <a--9->',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * <a1/>', ' * <a-a>', ' * <a--9->', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('09 Unusual HTML names, negative', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * <1a/>',
|
||||
' * <a.a>',
|
||||
' * <_a>',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * <1a/>', ' * <a.a>', ' * <_a>', ' */'].join('\n'));
|
||||
});
|
||||
|
|
|
@ -1,52 +1,25 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('00 InheritDoc tag: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc Class.member}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc package# Class . member}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@inheritDoc}', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@inheritDoc Class.member}', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@inheritDoc package# Class . member}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('01 InheritDoc tag: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc | link text}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc Class % junk}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritDoc}',
|
||||
' * {@inheritDoc}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * summary text',
|
||||
' * @remarks',
|
||||
' * {@inheritDoc}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@inheritDoc | link text}', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@inheritDoc Class % junk}', ' */'].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@inheritDoc}', ' * {@inheritDoc}', ' */'].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * summary text', ' * @remarks', ' * {@inheritDoc}', ' */'].join('\n')
|
||||
);
|
||||
|
||||
// Old API Extractor syntax
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@inheritdoc @scope/library:IDisposable.isDisposed}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@inheritdoc @scope/library:IDisposable.isDisposed}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,100 +1,96 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('00 Link text: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link http://example1.com}',
|
||||
' * {@link http://example2.com|}',
|
||||
' * {@link http://example3.com| }',
|
||||
' * {@link http://example4.com|link text}',
|
||||
' * 1{@link http://example5.com| link',
|
||||
' * text }2',
|
||||
' * 3{@link http://example5.com| ',
|
||||
' * link text ',
|
||||
' * }4',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link http://example1.com}',
|
||||
' * {@link http://example2.com|}',
|
||||
' * {@link http://example3.com| }',
|
||||
' * {@link http://example4.com|link text}',
|
||||
' * 1{@link http://example5.com| link',
|
||||
' * text }2',
|
||||
' * 3{@link http://example5.com| ',
|
||||
' * link text ',
|
||||
' * }4',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('01 Link text: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link}',
|
||||
' * {@link http://example1.com| link | text}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link}', ' * {@link http://example1.com| link | text}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('02 URL destination: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link http://example1.com}',
|
||||
' * {@link https://example2.com#hash|link text}',
|
||||
' * {@link customscheme://data}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link http://example1.com}',
|
||||
' * {@link https://example2.com#hash|link text}',
|
||||
' * {@link customscheme://data}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('03 URL destination: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link http://example1.com spaces}',
|
||||
' * {@link http://example2.com spaces|link text}',
|
||||
' * {@link ftp+ssh://example3.com}',
|
||||
' * {@link mailto:bob@example4.com}',
|
||||
' * {@link //example5.com}',
|
||||
' * {@link http://}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link http://example1.com spaces}',
|
||||
' * {@link http://example2.com spaces|link text}',
|
||||
' * {@link ftp+ssh://example3.com}',
|
||||
' * {@link mailto:bob@example4.com}',
|
||||
' * {@link //example5.com}',
|
||||
' * {@link http://}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 Declaration reference with package name: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link my-example1#}',
|
||||
' * {@link my-example2/path3#}',
|
||||
' * {@link my-example4/path5/path6#}',
|
||||
' * {@link @scope/my-example7/path8/path9#}',
|
||||
' * {@link @scope/my-example7#}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link my-example1#}',
|
||||
' * {@link my-example2/path3#}',
|
||||
' * {@link my-example4/path5/path6#}',
|
||||
' * {@link @scope/my-example7/path8/path9#}',
|
||||
' * {@link @scope/my-example7#}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('05 Declaration reference with package name: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link example1/#}',
|
||||
' * {@link example2/a//b#}',
|
||||
' * {@link @scope/ex@mple3#}',
|
||||
' * {@link @/example4#}',
|
||||
' * {@link @scope//my-example5#}',
|
||||
' * {@link @scope#}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link @#}',
|
||||
' * {@link #}',
|
||||
' * {@link #Button}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link example1/#}',
|
||||
' * {@link example2/a//b#}',
|
||||
' * {@link @scope/ex@mple3#}',
|
||||
' * {@link @/example4#}',
|
||||
' * {@link @scope//my-example5#}',
|
||||
' * {@link @scope#}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link @#}', ' * {@link #}', ' * {@link #Button}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('06 Declaration reference with import path only: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link ../path1#}',
|
||||
' * {@link ./path2#}',
|
||||
' * {@link ./path3/../path4#}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link ../path1#}', ' * {@link ./path2#}', ' * {@link ./path3/../path4#}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('07 Declaration reference with import path only: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link /path1#}',
|
||||
' * {@link /path1 path2#}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link /path1#}', ' * {@link /path1 path2#}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,118 +1,102 @@
|
|||
import { TestHelpers } from './TestHelpers';
|
||||
|
||||
test('00 Simple member references: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link Class1}',
|
||||
' * {@link Class2.member2}',
|
||||
' * {@link namespace3 . namespace4 ',
|
||||
' * . namespace5 | link text}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link Class1}',
|
||||
' * {@link Class2.member2}',
|
||||
' * {@link namespace3 . namespace4 ',
|
||||
' * . namespace5 | link text}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('01 Simple member references: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link Class1..member2}',
|
||||
' * {@link .member3}',
|
||||
' * {@link member4.}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link Class1..member2}', ' * {@link .member3}', ' * {@link member4.}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('02 System selectors: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (Class1:class)}',
|
||||
' * {@link (Class2:class).(member3:static)}',
|
||||
' * {@link Class4.(member5:static)}',
|
||||
' * {@link (Class6:class ) . ( member7:static)}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link (Class1:class)}',
|
||||
' * {@link (Class2:class).(member3:static)}',
|
||||
' * {@link Class4.(member5:static)}',
|
||||
' * {@link (Class6:class ) . ( member7:static)}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('03 System selectors: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (Class1:class}',
|
||||
' * {@link (Class2:class))}',
|
||||
' * {@link (Class3::class)}',
|
||||
' * {@link (Class4 class)}',
|
||||
' * {@link (member5:badname)}',
|
||||
' * {@link (Class6:class)(member:static)}',
|
||||
' * {@link Class7:class}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link (Class1:class}',
|
||||
' * {@link (Class2:class))}',
|
||||
' * {@link (Class3::class)}',
|
||||
' * {@link (Class4 class)}',
|
||||
' * {@link (member5:badname)}',
|
||||
' * {@link (Class6:class)(member:static)}',
|
||||
' * {@link Class7:class}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('04 Label selectors: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (Class1:LABEL1)}',
|
||||
' * {@link ( function2 : MY_LABEL2 ) }',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link (Class1:LABEL1)}', ' * {@link ( function2 : MY_LABEL2 ) }', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('05 Label selectors: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (Class1:Label)}',
|
||||
' * {@link (Class2:SPAß)}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
['/**', ' * {@link (Class1:Label)}', ' * {@link (Class2:SPAß)}', ' */'].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('06 Index selectors: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (function2 : 3 )}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@link (function2 : 3 )}', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('07 Index selectors: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link (function2:03)}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@link (function2:03)}', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('08 Unusual identifiers: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link Class$_1 . $_1member}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@link Class$_1 . $_1member}', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('09 Unusual identifiers: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link Class-1}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(['/**', ' * {@link Class-1}', ' */'].join('\n'));
|
||||
});
|
||||
|
||||
test('10 Quoted identifiers: positive examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link "static"}',
|
||||
' * {@link Class1 . "member"}',
|
||||
' * {@link Class2."|" | link text}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link "static"}',
|
||||
' * {@link Class1 . "member"}',
|
||||
' * {@link Class2."|" | link text}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
test('11 Quoted identifiers: negative examples', () => {
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot([
|
||||
'/**',
|
||||
' * {@link "static}',
|
||||
' * {@link Class1.""}',
|
||||
' * {@link Class2.interface}',
|
||||
' * {@link Class3.1}',
|
||||
' */'
|
||||
].join('\n'));
|
||||
TestHelpers.parseAndMatchNodeParserSnapshot(
|
||||
[
|
||||
'/**',
|
||||
' * {@link "static}',
|
||||
' * {@link Class1.""}',
|
||||
' * {@link Class2.interface}',
|
||||
' * {@link Class3.1}',
|
||||
' */'
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче