Invoke "prettier . --write" to prettify all source files

This commit is contained in:
Pete Gonzalez 2020-11-24 20:12:30 -08:00
Родитель 8fec2c3cab
Коммит 5e8673388d
108 изменённых файлов: 2633 добавлений и 2427 удалений

Просмотреть файл

@ -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}>
&copy; 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({

Просмотреть файл

@ -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 {
*/
'&copy;': 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')
);
});

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше