diff --git a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts
index ae3c0e04316..32ab70795bd 100644
--- a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts
+++ b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts
@@ -138,4 +138,12 @@ export class TypeScriptInternals {
}
return resolver;
}
+
+ /**
+ * Returns whether a variable is declared with the const keyword
+ */
+ public static isVarConst(node: ts.VariableDeclaration | ts.VariableDeclarationList): boolean {
+ // Compiler internal: https://github.com/microsoft/TypeScript/blob/71286e3d49c10e0e99faac360a6bbd40f12db7b6/src/compiler/utilities.ts#L925
+ return (ts as any).isVarConst(node);
+ }
}
diff --git a/apps/api-extractor/src/generators/ApiModelGenerator.ts b/apps/api-extractor/src/generators/ApiModelGenerator.ts
index 6c508a38b0f..7b3820653c0 100644
--- a/apps/api-extractor/src/generators/ApiModelGenerator.ts
+++ b/apps/api-extractor/src/generators/ApiModelGenerator.ts
@@ -43,6 +43,7 @@ import { DeclarationMetadata } from '../collector/DeclarationMetadata';
import { AstNamespaceImport } from '../analyzer/AstNamespaceImport';
import { AstEntity } from '../analyzer/AstEntity';
import { AstModule } from '../analyzer/AstModule';
+import { TypeScriptInternals } from '../analyzer/TypeScriptInternals';
export class ApiModelGenerator {
private readonly _collector: Collector;
@@ -851,6 +852,7 @@ export class ApiModelGenerator {
const isOptional: boolean =
(astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
const isProtected: boolean = (astDeclaration.modifierFlags & ts.ModifierFlags.Protected) !== 0;
+ const isReadonly: boolean = this._determineReadonly(astDeclaration);
apiProperty = new ApiProperty({
name,
@@ -859,6 +861,7 @@ export class ApiModelGenerator {
isProtected,
isStatic,
isOptional,
+ isReadonly,
excerptTokens,
propertyTypeTokenRange
});
@@ -895,6 +898,7 @@ export class ApiModelGenerator {
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
const isOptional: boolean =
(astDeclaration.astSymbol.followedSymbol.flags & ts.SymbolFlags.Optional) !== 0;
+ const isReadonly: boolean = this._determineReadonly(astDeclaration);
apiPropertySignature = new ApiPropertySignature({
name,
@@ -902,7 +906,8 @@ export class ApiModelGenerator {
releaseTag,
isOptional,
excerptTokens,
- propertyTypeTokenRange
+ propertyTypeTokenRange,
+ isReadonly
});
parentApiItem.addMember(apiPropertySignature);
@@ -981,8 +986,16 @@ export class ApiModelGenerator {
const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;
const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag;
+ const isReadonly: boolean = this._determineReadonly(astDeclaration);
- apiVariable = new ApiVariable({ name, docComment, releaseTag, excerptTokens, variableTypeTokenRange });
+ apiVariable = new ApiVariable({
+ name,
+ docComment,
+ releaseTag,
+ excerptTokens,
+ variableTypeTokenRange,
+ isReadonly
+ });
parentApiItem.addMember(apiVariable);
}
@@ -1055,4 +1068,22 @@ export class ApiModelGenerator {
}
return parameters;
}
+
+ private _determineReadonly(astDeclaration: AstDeclaration): boolean {
+ const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration);
+ const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment;
+ const declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration);
+ //Line 1: sees whether the readonly or const modifiers are present
+ //Line 2: sees if the TSDoc comment for @readonly is present
+ //Line 3: sees whether a getter is present for a property with no setter
+ //Line 4: sees if the var declaration has Const keyword
+ return (
+ (astDeclaration.modifierFlags & (ts.ModifierFlags.Readonly + ts.ModifierFlags.Const)) !== 0 ||
+ (docComment !== undefined && docComment.modifierTagSet.hasTagName('@readonly')) ||
+ (declarationMetadata.ancillaryDeclarations.length === 0 &&
+ astDeclaration.declaration.kind === ts.SyntaxKind.GetAccessor) ||
+ (ts.isVariableDeclaration(astDeclaration.declaration) &&
+ TypeScriptInternals.isVarConst(astDeclaration.declaration))
+ );
+ }
}
diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.json b/build-tests/api-documenter-test/etc/api-documenter-test.api.json
index c74a5c89274..9431f20e9fd 100644
--- a/build-tests/api-documenter-test/etc/api-documenter-test.api.json
+++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.json
@@ -209,6 +209,7 @@
"text": "number"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "constVariable",
"variableTypeTokenRange": {
@@ -248,6 +249,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "creationDate",
@@ -299,8 +301,8 @@
"text": "constructor();"
}
],
- "isProtected": false,
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": []
},
@@ -322,8 +324,8 @@
"text": ");"
}
],
- "isProtected": false,
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 2,
"parameters": [
{
@@ -401,16 +403,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "deprecatedExample"
},
{
@@ -447,14 +449,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -474,6 +475,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "exampleFunction"
},
{
@@ -502,14 +504,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 2,
"parameters": [
{
@@ -521,6 +522,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "exampleFunction"
},
{
@@ -571,14 +573,26 @@
"text": ";"
}
],
- "isOptional": false,
+ "typeParameters": [
+ {
+ "typeParameterName": "T",
+ "constraintTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "defaultTypeTokenRange": {
+ "startIndex": 4,
+ "endIndex": 5
+ }
+ }
+ ],
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 8,
"endIndex": 9
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -590,19 +604,7 @@
"isOptional": false
}
],
- "typeParameters": [
- {
- "typeParameterName": "T",
- "constraintTokenRange": {
- "startIndex": 1,
- "endIndex": 2
- },
- "defaultTypeTokenRange": {
- "startIndex": 4,
- "endIndex": 5
- }
- }
- ],
+ "isOptional": false,
"name": "genericWithConstraintAndDefault"
},
{
@@ -623,16 +625,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "interestingEdgeCases"
},
{
@@ -654,6 +656,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "malformedEvent",
@@ -683,6 +686,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "modifiedEvent",
@@ -719,14 +723,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -738,6 +741,7 @@
"isOptional": true
}
],
+ "isOptional": false,
"name": "optionalParamFunction"
},
{
@@ -758,6 +762,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "readonlyProperty",
@@ -787,6 +792,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "regularProperty",
@@ -797,6 +803,35 @@
"isStatic": false,
"isProtected": false
},
+ {
+ "kind": "Property",
+ "canonicalReference": "api-documenter-test!DocClass1.staticReadonlyThing:member",
+ "docComment": "",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "static readonly staticReadonlyThing: "
+ },
+ {
+ "kind": "Content",
+ "text": "boolean"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ }
+ ],
+ "isReadonly": true,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "staticReadonlyThing",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "isStatic": true,
+ "isProtected": false
+ },
{
"kind": "Method",
"canonicalReference": "api-documenter-test!DocClass1.sumWithExample:member(1)",
@@ -831,14 +866,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": true,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -858,6 +892,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "sumWithExample"
},
{
@@ -878,16 +913,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "tableExample"
},
{
@@ -912,6 +947,7 @@
"text": "\n\nset writeableProperty(value: string);"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "writeableProperty",
@@ -940,6 +976,7 @@
"text": ");"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "writeonlyProperty",
@@ -1200,6 +1237,7 @@
"text": "unique symbol"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "example",
"variableTypeTokenRange": {
@@ -1469,6 +1507,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "regularProperty",
@@ -1569,6 +1608,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "\"[not.a.symbol]\"",
@@ -1604,6 +1644,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "[EcmaSmbols.example]",
@@ -1743,6 +1784,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "redundantQuotes",
@@ -1785,6 +1827,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "Context",
@@ -1816,6 +1859,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "generic",
@@ -1842,6 +1886,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "numberOrFunction",
@@ -1868,6 +1913,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "stringOrNumber",
@@ -1910,6 +1956,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "regularProperty",
@@ -1957,6 +2004,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "arrayProperty",
@@ -2051,6 +2099,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "intersectionProperty",
@@ -2077,6 +2126,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "regularProperty",
@@ -2121,6 +2171,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "tupleProperty",
@@ -2161,6 +2212,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "typeReferenceProperty",
@@ -2197,6 +2249,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "unionProperty",
@@ -2239,6 +2292,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": true,
"releaseTag": "Public",
"name": "optionalField",
@@ -2293,6 +2347,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": true,
"releaseTag": "Public",
"name": "optionalReadonlyField",
@@ -2319,6 +2374,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": true,
"releaseTag": "Public",
"name": "optionalUndocumentedField",
@@ -2416,6 +2472,7 @@
"text": "boolean"
}
],
+ "isReadonly": false,
"releaseTag": "Public",
"name": "nestedVariable",
"variableTypeTokenRange": {
@@ -2464,14 +2521,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -2483,6 +2539,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "addHandler"
}
],
diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.md b/build-tests/api-documenter-test/etc/api-documenter-test.api.md
index 828c30e2583..e9e1412b999 100644
--- a/build-tests/api-documenter-test/etc/api-documenter-test.api.md
+++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.md
@@ -44,6 +44,8 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter
// (undocumented)
get readonlyProperty(): string;
regularProperty: SystemEvent;
+ // (undocumented)
+ static readonly staticReadonlyThing: boolean;
static sumWithExample(x: number, y: number): number;
tableExample(): void;
// (undocumented)
diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md
index 0c0a9e42f51..e6c3fa4b49d 100644
--- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md
+++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.md
@@ -37,6 +37,7 @@ The constructor for this class is marked as internal. Third-party code should no
| --- | --- | --- | --- |
| [readonlyProperty](./api-documenter-test.docclass1.readonlyproperty.md) | | string | |
| [regularProperty](./api-documenter-test.docclass1.regularproperty.md) | | [SystemEvent](./api-documenter-test.systemevent.md) | This is a regular property that happens to use the SystemEvent type. |
+| [staticReadonlyThing](./api-documenter-test.docclass1.staticreadonlything.md) | static
| boolean | |
| [writeableProperty](./api-documenter-test.docclass1.writeableproperty.md) | | string | |
| [writeonlyProperty](./api-documenter-test.docclass1.writeonlyproperty.md) | | string | API Extractor will surface an ae-missing-getter
finding for this property. |
diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.staticreadonlything.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.staticreadonlything.md
new file mode 100644
index 00000000000..ecb46a0668b
--- /dev/null
+++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docclass1.staticreadonlything.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [DocClass1](./api-documenter-test.docclass1.md) > [staticReadonlyThing](./api-documenter-test.docclass1.staticreadonlything.md)
+
+## DocClass1.staticReadonlyThing property
+
+Signature:
+
+```typescript
+static readonly staticReadonlyThing: boolean;
+```
diff --git a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml
index b02c6cb4ff3..5914b86ab2b 100644
--- a/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml
+++ b/build-tests/api-documenter-test/etc/yaml/api-documenter-test/docclass1.yml
@@ -45,6 +45,19 @@ properties:
content: 'regularProperty: SystemEvent;'
return:
type: ''
+ - name: staticReadonlyThing
+ uid: 'api-documenter-test!DocClass1.staticReadonlyThing:member'
+ package: api-documenter-test!
+ fullName: staticReadonlyThing
+ summary: ''
+ remarks: ''
+ example: []
+ isPreview: false
+ isDeprecated: false
+ syntax:
+ content: 'static readonly staticReadonlyThing: boolean;'
+ return:
+ type: boolean
- name: writeableProperty
uid: 'api-documenter-test!DocClass1#writeableProperty:member'
package: api-documenter-test!
diff --git a/build-tests/api-documenter-test/src/DocClass1.ts b/build-tests/api-documenter-test/src/DocClass1.ts
index 313a0f45a95..08c5764ca10 100644
--- a/build-tests/api-documenter-test/src/DocClass1.ts
+++ b/build-tests/api-documenter-test/src/DocClass1.ts
@@ -169,6 +169,8 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter
super();
}
+ static readonly staticReadonlyThing: boolean;
+
/**
* This is an overloaded function.
* @param a - the first string
diff --git a/build-tests/api-extractor-scenarios/config/build-config.json b/build-tests/api-extractor-scenarios/config/build-config.json
index 9a5de053b85..235cccb9382 100644
--- a/build-tests/api-extractor-scenarios/config/build-config.json
+++ b/build-tests/api-extractor-scenarios/config/build-config.json
@@ -36,6 +36,7 @@
"internationalCharacters",
"namedDefaultImport",
"preapproved",
+ "readonlyDeclarations",
"spanSorting",
"typeOf",
"typeOf2",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json
index 1ad471e5698..ddc84f4d697 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/apiItemKinds/api-extractor-scenarios.api.json
@@ -201,16 +201,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "member"
}
],
@@ -255,14 +255,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -274,6 +273,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "method1"
},
{
@@ -303,16 +303,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "method2"
}
],
@@ -427,6 +427,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "member",
@@ -465,6 +466,7 @@
"text": "object[]"
}
],
+ "isReadonly": false,
"releaseTag": "Public",
"name": "constVariable",
"variableTypeTokenRange": {
@@ -486,6 +488,7 @@
"text": "object[]"
}
],
+ "isReadonly": false,
"releaseTag": "Public",
"name": "variable",
"variableTypeTokenRange": {
@@ -604,16 +607,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "member"
},
{
@@ -642,14 +645,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -661,6 +663,7 @@
"isOptional": true
}
],
+ "isOptional": false,
"name": "optionalParamMethod"
},
{
@@ -681,6 +684,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "readonlyProperty",
@@ -701,6 +705,7 @@
"text": "readonly someReadonlyProp = 5;"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "someReadonlyProp",
@@ -729,6 +734,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "someReadonlyPropWithType",
@@ -761,6 +767,7 @@
"text": "\n\nset writeableProperty(value: string);"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "writeableProperty",
@@ -788,6 +795,7 @@
"text": "string"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "VARIABLE",
"variableTypeTokenRange": {
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json
index ab02095254d..bccae8ebf56 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/bundledPackages/api-extractor-scenarios.api.json
@@ -272,6 +272,7 @@
"text": ";"
}
],
+ "isReadonly": true,
"isOptional": false,
"releaseTag": "Public",
"name": "readonlyProperty",
@@ -300,6 +301,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "writeableProperty",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json
index 137bc2cf3cb..115ef5174f8 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport/api-extractor-scenarios.api.json
@@ -202,6 +202,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "containingFolder",
@@ -251,6 +252,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "containingFolder",
@@ -284,6 +286,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "files",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json
index 52cb2b531f9..ee1019ead38 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/circularImport2/api-extractor-scenarios.api.json
@@ -232,6 +232,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "containingFolder",
@@ -281,6 +282,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "containingFolder",
@@ -314,6 +316,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "files",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json
index e7e25bbfac5..cf3343522f6 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json
@@ -184,6 +184,7 @@
"text": "() => void"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "defaultFunctionStatement",
"variableTypeTokenRange": {
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json
index 8a31e30a029..6ad2778b65e 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json
@@ -184,6 +184,7 @@
"text": "\"literal\""
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "_default",
"variableTypeTokenRange": {
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json
index 760eaee1338..82a4e4577d3 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences/api-extractor-scenarios.api.json
@@ -276,14 +276,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Beta",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -295,6 +294,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "myMethod"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json
index 185efd3af43..d9924f69917 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences2/api-extractor-scenarios.api.json
@@ -201,16 +201,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "methodA1"
},
{
@@ -231,16 +231,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "methodA3"
}
],
@@ -277,16 +277,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "methodB2"
},
{
@@ -307,16 +307,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "methodB4"
}
],
@@ -353,16 +353,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "method1"
},
{
@@ -383,16 +383,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "method2"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json
index 53224316fe5..158b62ad07d 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/docReferences3/api-extractor-scenarios.api.json
@@ -201,6 +201,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "myProperty",
@@ -256,16 +257,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "myMethod"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType/api-extractor-scenarios.api.json
index 0f5d2794d44..69c76780983 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType/api-extractor-scenarios.api.json
@@ -206,6 +206,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "lib1",
@@ -239,6 +240,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "lib2",
@@ -272,6 +274,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "lib3",
@@ -305,6 +308,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "options",
@@ -338,6 +342,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "reExport",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType2/api-extractor-scenarios.api.json
index c7bdadc9c91..f958f2f2214 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType2/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType2/api-extractor-scenarios.api.json
@@ -210,6 +210,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "dottedImportType",
@@ -245,6 +246,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "dottedImportType2",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType3/api-extractor-scenarios.api.json
index d6b16a75d00..e2e5296d90c 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType3/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/dynamicImportType3/api-extractor-scenarios.api.json
@@ -219,6 +219,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "generic",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/excerptTokens/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/excerptTokens/api-extractor-scenarios.api.json
index 3f533ee760a..c145dad23bb 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/excerptTokens/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/excerptTokens/api-extractor-scenarios.api.json
@@ -184,6 +184,7 @@
"text": "number"
}
],
+ "isReadonly": false,
"releaseTag": "Public",
"name": "MY_CONSTANT",
"variableTypeTokenRange": {
@@ -238,14 +239,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -265,6 +265,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "someMethod"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json
index e472b4d3470..fbc45d3d9ab 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/exportEquals/api-extractor-scenarios.api.json
@@ -202,6 +202,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "context",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportStarAs/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportStarAs/api-extractor-scenarios.api.json
index 677c43c0503..96cc42782c0 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportStarAs/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/exportImportStarAs/api-extractor-scenarios.api.json
@@ -252,6 +252,7 @@
"text": "string"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "calucatorVersion",
"variableTypeTokenRange": {
@@ -403,6 +404,7 @@
"text": "string"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "calucatorVersion",
"variableTypeTokenRange": {
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json
index 724f1432540..78b861a36dd 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/functionOverload/api-extractor-scenarios.api.json
@@ -397,14 +397,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Beta",
+ "isProtected": false,
"overloadIndex": 2,
"parameters": [
{
@@ -424,6 +423,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "combine"
},
{
@@ -460,14 +460,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 5,
"endIndex": 6
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 3,
"parameters": [
{
@@ -487,6 +486,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "combine"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json
index 049b1aa274e..e6a1dd9f430 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/inconsistentReleaseTags/api-extractor-scenarios.api.json
@@ -201,6 +201,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Beta",
"name": "x",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json
index f51e8847ea1..e04bf18af4a 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/internationalCharacters/api-extractor-scenarios.api.json
@@ -210,16 +210,6 @@
"text": ";"
}
],
- "isOptional": false,
- "isStatic": false,
- "isProtected": false,
- "returnTypeTokenRange": {
- "startIndex": 3,
- "endIndex": 4
- },
- "releaseTag": "Public",
- "overloadIndex": 1,
- "parameters": [],
"typeParameters": [
{
"typeParameterName": "T",
@@ -233,6 +223,16 @@
}
}
],
+ "isStatic": false,
+ "returnTypeTokenRange": {
+ "startIndex": 3,
+ "endIndex": 4
+ },
+ "releaseTag": "Public",
+ "isProtected": false,
+ "overloadIndex": 1,
+ "parameters": [],
+ "isOptional": false,
"name": "\"invalid chars\""
},
{
@@ -262,14 +262,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -281,6 +280,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "memberĪ"
},
{
@@ -301,16 +301,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "validChars"
}
],
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/namedDefaultImport/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/namedDefaultImport/api-extractor-scenarios.api.json
index 29b8e929d81..e5fc5f7052d 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/namedDefaultImport/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/namedDefaultImport/api-extractor-scenarios.api.json
@@ -206,6 +206,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "dynamicImport",
@@ -233,6 +234,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "namedImport",
@@ -260,6 +262,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "reExport",
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.json
new file mode 100644
index 00000000000..c2084c4a386
--- /dev/null
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.json
@@ -0,0 +1,386 @@
+{
+ "metadata": {
+ "toolPackage": "@microsoft/api-extractor",
+ "toolVersion": "[test mode]",
+ "schemaVersion": 1006,
+ "oldestForwardsCompatibleVersion": 1001,
+ "tsdocConfig": {
+ "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
+ "noStandardTags": true,
+ "tagDefinitions": [
+ {
+ "tagName": "@alpha",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@beta",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@defaultValue",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@decorator",
+ "syntaxKind": "block",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@deprecated",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@eventProperty",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@example",
+ "syntaxKind": "block",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@experimental",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@inheritDoc",
+ "syntaxKind": "inline"
+ },
+ {
+ "tagName": "@internal",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@label",
+ "syntaxKind": "inline"
+ },
+ {
+ "tagName": "@link",
+ "syntaxKind": "inline",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@override",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@packageDocumentation",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@param",
+ "syntaxKind": "block",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@privateRemarks",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@public",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@readonly",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@remarks",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@returns",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@sealed",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@see",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@throws",
+ "syntaxKind": "block",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@typeParam",
+ "syntaxKind": "block",
+ "allowMultiple": true
+ },
+ {
+ "tagName": "@virtual",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@betaDocumentation",
+ "syntaxKind": "modifier"
+ },
+ {
+ "tagName": "@internalRemarks",
+ "syntaxKind": "block"
+ },
+ {
+ "tagName": "@preapproved",
+ "syntaxKind": "modifier"
+ }
+ ],
+ "supportForTags": {
+ "@alpha": true,
+ "@beta": true,
+ "@defaultValue": true,
+ "@decorator": true,
+ "@deprecated": true,
+ "@eventProperty": true,
+ "@example": true,
+ "@experimental": true,
+ "@inheritDoc": true,
+ "@internal": true,
+ "@label": true,
+ "@link": true,
+ "@override": true,
+ "@packageDocumentation": true,
+ "@param": true,
+ "@privateRemarks": true,
+ "@public": true,
+ "@readonly": true,
+ "@remarks": true,
+ "@returns": true,
+ "@sealed": true,
+ "@see": true,
+ "@throws": true,
+ "@typeParam": true,
+ "@virtual": true,
+ "@betaDocumentation": true,
+ "@internalRemarks": true,
+ "@preapproved": true
+ },
+ "reportUnsupportedHtmlElements": false
+ }
+ },
+ "kind": "Package",
+ "canonicalReference": "api-extractor-scenarios!",
+ "docComment": "",
+ "name": "api-extractor-scenarios",
+ "members": [
+ {
+ "kind": "EntryPoint",
+ "canonicalReference": "api-extractor-scenarios!",
+ "name": "",
+ "members": [
+ {
+ "kind": "Interface",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface",
+ "docComment": "/**\n * @public\n */\n",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "export interface _IInternalThing "
+ }
+ ],
+ "releaseTag": "Public",
+ "name": "_IInternalThing",
+ "members": [
+ {
+ "kind": "PropertySignature",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing#title:member",
+ "docComment": "",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "title: "
+ },
+ {
+ "kind": "Content",
+ "text": "string"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ }
+ ],
+ "isReadonly": false,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "title",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ }
+ }
+ ],
+ "extendsTokenRanges": []
+ },
+ {
+ "kind": "Variable",
+ "canonicalReference": "api-extractor-scenarios!FOO:var",
+ "docComment": "/**\n * @public\n */\n",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "FOO = \"foo\""
+ }
+ ],
+ "isReadonly": true,
+ "releaseTag": "Public",
+ "name": "FOO",
+ "variableTypeTokenRange": {
+ "startIndex": 0,
+ "endIndex": 0
+ }
+ },
+ {
+ "kind": "Class",
+ "canonicalReference": "api-extractor-scenarios!MyClass:class",
+ "docComment": "/**\n * @public\n */\n",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "export declare class MyClass "
+ }
+ ],
+ "releaseTag": "Public",
+ "name": "MyClass",
+ "members": [
+ {
+ "kind": "Property",
+ "canonicalReference": "api-extractor-scenarios!MyClass#_onlyHasGetterThing:member",
+ "docComment": "",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "get _onlyHasGetterThing(): "
+ },
+ {
+ "kind": "Reference",
+ "text": "_IInternalThing",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ }
+ ],
+ "isReadonly": true,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "_onlyHasGetterThing",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "isStatic": false,
+ "isProtected": false
+ },
+ {
+ "kind": "Property",
+ "canonicalReference": "api-extractor-scenarios!MyClass#_writableThing:member",
+ "docComment": "",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "get _writableThing(): "
+ },
+ {
+ "kind": "Reference",
+ "text": "_IInternalThing",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ },
+ {
+ "kind": "Content",
+ "text": "\n\nset _writableThing(value: "
+ },
+ {
+ "kind": "Reference",
+ "text": "_IInternalThing",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface"
+ },
+ {
+ "kind": "Content",
+ "text": ");"
+ }
+ ],
+ "isReadonly": false,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "_writableThing",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "isStatic": false,
+ "isProtected": false
+ },
+ {
+ "kind": "Property",
+ "canonicalReference": "api-extractor-scenarios!MyClass.declaredReadonlyThing:member",
+ "docComment": "",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "static readonly declaredReadonlyThing: "
+ },
+ {
+ "kind": "Reference",
+ "text": "_IInternalThing",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ }
+ ],
+ "isReadonly": true,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "declaredReadonlyThing",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "isStatic": true,
+ "isProtected": false
+ },
+ {
+ "kind": "Property",
+ "canonicalReference": "api-extractor-scenarios!MyClass#tsDocReadonlyThing:member",
+ "docComment": "/**\n * Technically isn't but for testing purposes\n *\n * @readonly\n */\n",
+ "excerptTokens": [
+ {
+ "kind": "Content",
+ "text": "tsDocReadonlyThing: "
+ },
+ {
+ "kind": "Reference",
+ "text": "_IInternalThing",
+ "canonicalReference": "api-extractor-scenarios!_IInternalThing:interface"
+ },
+ {
+ "kind": "Content",
+ "text": ";"
+ }
+ ],
+ "isReadonly": true,
+ "isOptional": false,
+ "releaseTag": "Public",
+ "name": "tsDocReadonlyThing",
+ "propertyTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "isStatic": false,
+ "isProtected": false
+ }
+ ],
+ "implementsTokenRanges": []
+ }
+ ]
+ }
+ ]
+}
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.md
new file mode 100644
index 00000000000..a3b886324d9
--- /dev/null
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/api-extractor-scenarios.api.md
@@ -0,0 +1,30 @@
+## API Report File for "api-extractor-scenarios"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+
+// @public (undocumented)
+export const FOO = "foo";
+
+// @public (undocumented)
+export interface _IInternalThing {
+ // (undocumented)
+ title: string;
+}
+
+// @public (undocumented)
+export class MyClass {
+ // (undocumented)
+ static readonly declaredReadonlyThing: _IInternalThing;
+ // (undocumented)
+ get _onlyHasGetterThing(): _IInternalThing;
+ tsDocReadonlyThing: _IInternalThing;
+ // (undocumented)
+ get _writableThing(): _IInternalThing;
+ set _writableThing(value: _IInternalThing);
+}
+
+// (No @packageDocumentation comment for this package)
+
+```
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/rollup.d.ts
new file mode 100644
index 00000000000..d133028f380
--- /dev/null
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/readonlyDeclarations/rollup.d.ts
@@ -0,0 +1,22 @@
+/** @public */
+export declare const FOO = "foo";
+
+/** @public */
+export declare interface _IInternalThing {
+ title: string;
+}
+
+/** @public */
+export declare class MyClass {
+ get _writableThing(): _IInternalThing;
+ set _writableThing(value: _IInternalThing);
+ get _onlyHasGetterThing(): _IInternalThing;
+ static readonly declaredReadonlyThing: _IInternalThing;
+ /**
+ * Technically isn't but for testing purposes
+ * @readonly
+ */
+ tsDocReadonlyThing: _IInternalThing;
+}
+
+export { }
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/spanSorting/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/spanSorting/api-extractor-scenarios.api.json
index 6fbf248aaa0..d5cafe486ab 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/spanSorting/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/spanSorting/api-extractor-scenarios.api.json
@@ -201,6 +201,7 @@
"text": ";"
}
],
+ "isReadonly": false,
"isOptional": false,
"releaseTag": "Public",
"name": "member1",
@@ -234,16 +235,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 3
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "member2"
}
],
@@ -288,14 +289,13 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 3,
"endIndex": 4
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [
{
@@ -307,6 +307,7 @@
"isOptional": false
}
],
+ "isOptional": false,
"name": "tryLoadFromFile"
}
],
@@ -343,16 +344,16 @@
"text": ";"
}
],
- "isOptional": false,
"isStatic": false,
- "isProtected": false,
"returnTypeTokenRange": {
"startIndex": 1,
"endIndex": 2
},
"releaseTag": "Public",
+ "isProtected": false,
"overloadIndex": 1,
"parameters": [],
+ "isOptional": false,
"name": "member1"
}
],
@@ -372,6 +373,7 @@
"text": "(o: {\n a: number;\n b(): string;\n}) => void"
}
],
+ "isReadonly": true,
"releaseTag": "Public",
"name": "exampleD",
"variableTypeTokenRange": {
diff --git a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json
index 50102ff1a5f..74e92fe01a7 100644
--- a/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json
+++ b/build-tests/api-extractor-scenarios/etc/test-outputs/typeParameters/api-extractor-scenarios.api.json
@@ -201,16 +201,6 @@
"text": ";"
}
],
- "isOptional": false,
- "isStatic": false,
- "isProtected": false,
- "returnTypeTokenRange": {
- "startIndex": 1,
- "endIndex": 2
- },
- "releaseTag": "Public",
- "overloadIndex": 1,
- "parameters": [],
"typeParameters": [
{
"typeParameterName": "T",
@@ -224,6 +214,16 @@
}
}
],
+ "isStatic": false,
+ "returnTypeTokenRange": {
+ "startIndex": 1,
+ "endIndex": 2
+ },
+ "releaseTag": "Public",
+ "isProtected": false,
+ "overloadIndex": 1,
+ "parameters": [],
+ "isOptional": false,
"name": "method"
}
],
diff --git a/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.ts b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.ts
new file mode 100644
index 00000000000..9d627cc9b4c
--- /dev/null
+++ b/build-tests/api-extractor-scenarios/src/readonlyDeclarations/index.ts
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+/** @public */
+export interface _IInternalThing {
+ title: string;
+}
+
+/** @public */
+export const FOO = 'foo';
+
+/** @public */
+export class MyClass {
+ public get _writableThing(): _IInternalThing {
+ return { title: 'thing' };
+ }
+
+ public set _writableThing(value: _IInternalThing) {}
+
+ public get _onlyHasGetterThing(): _IInternalThing {
+ return { title: 'thing' };
+ }
+
+ static readonly declaredReadonlyThing: _IInternalThing;
+
+ /**
+ * Technically isn't but for testing purposes
+ * @readonly
+ */
+ public tsDocReadonlyThing: _IInternalThing;
+}
diff --git a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml
index 5291a3421c7..9fab90318d7 100644
--- a/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml
+++ b/build-tests/install-test-workspace/workspace/common/pnpm-lock.yaml
@@ -5,13 +5,13 @@ importers:
typescript-newest-test:
specifiers:
'@rushstack/eslint-config': file:rushstack-eslint-config-2.6.0.tgz
- '@rushstack/heft': file:rushstack-heft-0.45.4.tgz
+ '@rushstack/heft': file:rushstack-heft-0.45.5.tgz
eslint: ~8.7.0
tslint: ~5.20.1
typescript: ~4.6.3
devDependencies:
'@rushstack/eslint-config': file:../temp/tarballs/rushstack-eslint-config-2.6.0.tgz_eslint@8.7.0+typescript@4.6.3
- '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.45.4.tgz
+ '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.45.5.tgz
eslint: 8.7.0
tslint: 5.20.1_typescript@4.6.3
typescript: 4.6.3
@@ -19,13 +19,13 @@ importers:
typescript-v3-test:
specifiers:
'@rushstack/eslint-config': file:rushstack-eslint-config-2.6.0.tgz
- '@rushstack/heft': file:rushstack-heft-0.45.4.tgz
+ '@rushstack/heft': file:rushstack-heft-0.45.5.tgz
eslint: ~8.7.0
tslint: ~5.20.1
typescript: ~4.6.3
devDependencies:
'@rushstack/eslint-config': file:../temp/tarballs/rushstack-eslint-config-2.6.0.tgz_eslint@8.7.0+typescript@4.6.3
- '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.45.4.tgz
+ '@rushstack/heft': file:../temp/tarballs/rushstack-heft-0.45.5.tgz
eslint: 8.7.0
tslint: 5.20.1_typescript@4.6.3
typescript: 4.6.3
@@ -831,7 +831,7 @@ packages:
dev: true
/glob-escape/0.0.2:
- resolution: {integrity: sha1-nCf3gh7RwTd1gvPv2VWOP2dWKO0=}
+ resolution: {integrity: sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==}
engines: {node: '>= 0.10'}
dev: true
@@ -850,7 +850,7 @@ packages:
dev: true
/glob/7.0.6:
- resolution: {integrity: sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=}
+ resolution: {integrity: sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
@@ -1073,7 +1073,7 @@ packages:
dev: true
/jju/1.4.0:
- resolution: {integrity: sha1-o6vicYryQaKykE+EpiWXDzia4yo=}
+ resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
dev: true
/js-tokens/4.0.0:
@@ -1104,7 +1104,7 @@ packages:
dev: true
/jsonfile/4.0.0:
- resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=}
+ resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
optionalDependencies:
graceful-fs: 4.2.6
dev: true
@@ -1131,11 +1131,11 @@ packages:
dev: true
/lodash.get/4.4.2:
- resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=}
+ resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
dev: true
/lodash.isequal/4.5.0:
- resolution: {integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=}
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
dev: true
/lodash.merge/4.6.2:
@@ -1200,7 +1200,7 @@ packages:
dev: true
/object-assign/4.1.1:
- resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
dev: true
@@ -1258,7 +1258,7 @@ packages:
dev: true
/once/1.4.0:
- resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
@@ -1753,10 +1753,10 @@ packages:
- typescript
dev: true
- file:../temp/tarballs/rushstack-heft-0.45.4.tgz:
- resolution: {tarball: file:../temp/tarballs/rushstack-heft-0.45.4.tgz}
+ file:../temp/tarballs/rushstack-heft-0.45.5.tgz:
+ resolution: {tarball: file:../temp/tarballs/rushstack-heft-0.45.5.tgz}
name: '@rushstack/heft'
- version: 0.45.4
+ version: 0.45.5
engines: {node: '>=10.13.0'}
hasBin: true
dependencies:
diff --git a/common/changes/@microsoft/api-extractor-model/api-readonly-mixin_2022-05-19-20-18.json b/common/changes/@microsoft/api-extractor-model/api-readonly-mixin_2022-05-19-20-18.json
new file mode 100644
index 00000000000..b0380433357
--- /dev/null
+++ b/common/changes/@microsoft/api-extractor-model/api-readonly-mixin_2022-05-19-20-18.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@microsoft/api-extractor-model",
+ "comment": "Add an \"isReadonly\" field to ApiProperty, ApiPropertySignature, and ApiVariable",
+ "type": "minor"
+ }
+ ],
+ "packageName": "@microsoft/api-extractor-model"
+}
\ No newline at end of file
diff --git a/common/changes/@microsoft/api-extractor-model/protected-mixin_2022-05-20-22-50.json b/common/changes/@microsoft/api-extractor-model/protected-mixin_2022-05-20-22-50.json
index dec7b0ee3ed..8d4390c4dbd 100644
--- a/common/changes/@microsoft/api-extractor-model/protected-mixin_2022-05-20-22-50.json
+++ b/common/changes/@microsoft/api-extractor-model/protected-mixin_2022-05-20-22-50.json
@@ -2,7 +2,7 @@
"changes": [
{
"packageName": "@microsoft/api-extractor-model",
- "comment": "Add parsing logic to parse whether a class constructor, property, or method has the 'protected' modifier.",
+ "comment": "Add an \"isProtected\" field to ApiConstructor, ApiMethod, and ApiProperty",
"type": "minor"
}
],
diff --git a/common/changes/@microsoft/api-extractor/api-readonly-mixin_2022-05-19-20-18.json b/common/changes/@microsoft/api-extractor/api-readonly-mixin_2022-05-19-20-18.json
new file mode 100644
index 00000000000..000ad71a5d1
--- /dev/null
+++ b/common/changes/@microsoft/api-extractor/api-readonly-mixin_2022-05-19-20-18.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@microsoft/api-extractor",
+ "comment": "Add an \"isReadonly\" field to the doc model to indicate whether a property or variable is readonly",
+ "type": "minor"
+ }
+ ],
+ "packageName": "@microsoft/api-extractor"
+}
\ No newline at end of file
diff --git a/common/changes/@microsoft/api-extractor/protected-mixin_2022-05-20-22-50.json b/common/changes/@microsoft/api-extractor/protected-mixin_2022-05-20-22-50.json
index bf444adf5ac..1099b359645 100644
--- a/common/changes/@microsoft/api-extractor/protected-mixin_2022-05-20-22-50.json
+++ b/common/changes/@microsoft/api-extractor/protected-mixin_2022-05-20-22-50.json
@@ -2,7 +2,7 @@
"changes": [
{
"packageName": "@microsoft/api-extractor",
- "comment": "Add an ApiParameterMixin that adds an isProtected parameter to class constructor, property, and method API items.",
+ "comment": "Add an \"isProtected\" field to the doc model to indicate protected class members",
"type": "minor"
}
],
diff --git a/common/reviews/api/api-extractor-model.api.md b/common/reviews/api/api-extractor-model.api.md
index 51e591204da..3e248e4d580 100644
--- a/common/reviews/api/api-extractor-model.api.md
+++ b/common/reviews/api/api-extractor-model.api.md
@@ -522,6 +522,21 @@ export namespace ApiProtectedMixin {
export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiProtectedMixin;
}
+// @public
+export function ApiReadonlyMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiReadonlyMixin);
+
+// @public
+export interface ApiReadonlyMixin extends ApiItem {
+ readonly isReadonly: boolean;
+ // (undocumented)
+ serializeInto(jsonObject: Partial): void;
+}
+
+// @public
+export namespace ApiReadonlyMixin {
+ export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReadonlyMixin;
+}
+
// @public
export function ApiReleaseTagMixin(baseClass: TBaseClass): TBaseClass & (new (...args: any[]) => ApiReleaseTagMixin);
@@ -736,7 +751,7 @@ export interface IApiItemOptions {
}
// @public
-export interface IApiMethodOptions extends IApiNameMixinOptions, IApiTypeParameterListMixinOptions, IApiParameterListMixinOptions, IApiProtectedMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiStaticMixinOptions, IApiOptionalMixinOptions, IApiDeclaredItemOptions {
+export interface IApiMethodOptions extends IApiNameMixinOptions, IApiOptionalMixinOptions, IApiParameterListMixinOptions, IApiProtectedMixinOptions, IApiReleaseTagMixinOptions, IApiReturnTypeMixinOptions, IApiStaticMixinOptions, IApiTypeParameterListMixinOptions, IApiDeclaredItemOptions {
}
// @public (undocumented)
@@ -791,7 +806,7 @@ export interface IApiParameterOptions {
}
// @public
-export interface IApiPropertyItemOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiOptionalMixinOptions, IApiDeclaredItemOptions {
+export interface IApiPropertyItemOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiOptionalMixinOptions, IApiReadonlyMixinOptions, IApiDeclaredItemOptions {
// (undocumented)
propertyTypeTokenRange: IExcerptTokenRange;
}
@@ -810,6 +825,12 @@ export interface IApiProtectedMixinOptions extends IApiItemOptions {
isProtected: boolean;
}
+// @public
+export interface IApiReadonlyMixinOptions extends IApiItemOptions {
+ // (undocumented)
+ isReadonly: boolean;
+}
+
// @public
export interface IApiReleaseTagMixinOptions extends IApiItemOptions {
// (undocumented)
@@ -851,7 +872,7 @@ export interface IApiTypeParameterOptions {
}
// @public
-export interface IApiVariableOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiDeclaredItemOptions {
+export interface IApiVariableOptions extends IApiNameMixinOptions, IApiReleaseTagMixinOptions, IApiReadonlyMixinOptions, IApiDeclaredItemOptions {
// (undocumented)
variableTypeTokenRange: IExcerptTokenRange;
}
diff --git a/libraries/api-extractor-model/src/index.ts b/libraries/api-extractor-model/src/index.ts
index f3c7c610922..41e9d88d1e6 100644
--- a/libraries/api-extractor-model/src/index.ts
+++ b/libraries/api-extractor-model/src/index.ts
@@ -37,6 +37,7 @@ export { IApiReturnTypeMixinOptions, ApiReturnTypeMixin } from './mixins/ApiRetu
export { IApiStaticMixinOptions, ApiStaticMixin } from './mixins/ApiStaticMixin';
export { IApiNameMixinOptions, ApiNameMixin } from './mixins/ApiNameMixin';
export { IApiOptionalMixinOptions, ApiOptionalMixin } from './mixins/ApiOptionalMixin';
+export { IApiReadonlyMixinOptions, ApiReadonlyMixin } from './mixins/ApiReadonlyMixin';
export { ExcerptTokenKind, IExcerptTokenRange, IExcerptToken, ExcerptToken, Excerpt } from './mixins/Excerpt';
export { Constructor, PropertiesOf } from './mixins/Mixin';
diff --git a/libraries/api-extractor-model/src/items/ApiPropertyItem.ts b/libraries/api-extractor-model/src/items/ApiPropertyItem.ts
index 9290f5deff4..9a9cfefd650 100644
--- a/libraries/api-extractor-model/src/items/ApiPropertyItem.ts
+++ b/libraries/api-extractor-model/src/items/ApiPropertyItem.ts
@@ -7,6 +7,7 @@ import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiRel
import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin';
import { DeserializerContext } from '../model/DeserializerContext';
import { ApiOptionalMixin, IApiOptionalMixinOptions } from '../mixins/ApiOptionalMixin';
+import { ApiReadonlyMixin, IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin';
/**
* Constructor options for {@link ApiPropertyItem}.
@@ -16,6 +17,7 @@ export interface IApiPropertyItemOptions
extends IApiNameMixinOptions,
IApiReleaseTagMixinOptions,
IApiOptionalMixinOptions,
+ IApiReadonlyMixinOptions,
IApiDeclaredItemOptions {
propertyTypeTokenRange: IExcerptTokenRange;
}
@@ -29,7 +31,9 @@ export interface IApiPropertyItemJson extends IApiDeclaredItemJson {
*
* @public
*/
-export class ApiPropertyItem extends ApiNameMixin(ApiReleaseTagMixin(ApiOptionalMixin(ApiDeclaredItem))) {
+export class ApiPropertyItem extends ApiNameMixin(
+ ApiReleaseTagMixin(ApiOptionalMixin(ApiReadonlyMixin(ApiDeclaredItem)))
+) {
/**
* An {@link Excerpt} that describes the type of the property.
*/
diff --git a/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts
new file mode 100644
index 00000000000..45de9a603bd
--- /dev/null
+++ b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts
@@ -0,0 +1,135 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.s
+
+import { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem';
+import { DeserializerContext } from '../model/DeserializerContext';
+
+/**
+ * Constructor options for {@link (ApiReadonlyMixin:interface)}.
+ * @public
+ */
+export interface IApiReadonlyMixinOptions extends IApiItemOptions {
+ isReadonly: boolean;
+}
+
+export interface IApiReadonlyMixinJson extends IApiItemJson {
+ isReadonly: boolean;
+}
+
+const _isReadonly: unique symbol = Symbol('ApiReadonlyMixin._isReadonly');
+
+/**
+ * The mixin base class for API items that cannot be modified after instantiation.
+ * Examples such as the readonly modifier and only having a getter but no setter.
+ *
+ * @remarks
+ *
+ * This is part of the {@link ApiModel} hierarchy of classes, which are serializable representations of
+ * API declarations. The non-abstract classes (e.g. `ApiClass`, `ApiEnum`, `ApiInterface`, etc.) use
+ * TypeScript "mixin" functions (e.g. `ApiDeclaredItem`, `ApiItemContainerMixin`, etc.) to add various
+ * features that cannot be represented as a normal inheritance chain (since TypeScript does not allow a child class
+ * to extend more than one base class). The "mixin" is a TypeScript merged declaration with three components:
+ * the function that generates a subclass, an interface that describes the members of the subclass, and
+ * a namespace containing static members of the class.
+ *
+ * @public
+ */
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export interface ApiReadonlyMixin extends ApiItem {
+ /**
+ * Indicates that the API item's value cannot be assigned by an external consumer.
+ *
+ * @remarks
+ * Examples of API items that would be considered "read only" by API Extractor:
+ *
+ * - A class or interface's property that has the `readonly` modifier.
+ *
+ * - A variable that has the `const` modifier.
+ *
+ * - A property or variable whose TSDoc comment includes the `@readonly` tag.
+ *
+ * - A property declaration with a getter but no setter.
+ *
+ * Note that if the `readonly` keyword appears in a type annotation, this does not
+ * guarantee that that the API item will be considered readonly. For example:
+ *
+ * ```ts
+ * declare class C {
+ * // isReadonly=false in this case, because C.x is assignable
+ * public x: readonly string[];
+ * }
+ * ```
+ */
+ readonly isReadonly: boolean;
+
+ serializeInto(jsonObject: Partial): void;
+}
+
+/**
+ * Mixin function for {@link (ApiReadonlyMixin:interface)}.
+ *
+ * @param baseClass - The base class to be extended
+ * @returns A child class that extends baseClass, adding the {@link (ApiReadonlyMixin:interface)}
+ * functionality.
+ *
+ * @public
+ */
+export function ApiReadonlyMixin(
+ baseClass: TBaseClass
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+): TBaseClass & (new (...args: any[]) => ApiReadonlyMixin) {
+ class MixedClass extends baseClass implements ApiReadonlyMixin {
+ public [_isReadonly]: boolean;
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public constructor(...args: any[]) {
+ super(...args);
+
+ const options: IApiReadonlyMixinOptions = args[0];
+ this[_isReadonly] = options.isReadonly;
+ }
+
+ /** @override */
+ public static onDeserializeInto(
+ options: Partial,
+ context: DeserializerContext,
+ jsonObject: IApiReadonlyMixinJson
+ ): void {
+ baseClass.onDeserializeInto(options, context, jsonObject);
+
+ options.isReadonly = jsonObject.isReadonly || false;
+ }
+
+ public get isReadonly(): boolean {
+ return this[_isReadonly];
+ }
+
+ /** @override */
+ public serializeInto(jsonObject: Partial): void {
+ super.serializeInto(jsonObject);
+
+ jsonObject.isReadonly = this.isReadonly;
+ }
+ }
+
+ return MixedClass;
+}
+
+/**
+ * Static members for {@link (ApiReadonlyMixin:interface)}.
+ * @public
+ */
+export namespace ApiReadonlyMixin {
+ /**
+ * A type guard that tests whether the specified `ApiItem` subclass extends the `ApiReadonlyMixin` mixin.
+ *
+ * @remarks
+ *
+ * The JavaScript `instanceof` operator cannot be used to test for mixin inheritance, because each invocation of
+ * the mixin function produces a different subclass. (This could be mitigated by `Symbol.hasInstance`, however
+ * the TypeScript type system cannot invoke a runtime test.)
+ */
+ export function isBaseClassOf(apiItem: ApiItem): apiItem is ApiReadonlyMixin {
+ return apiItem.hasOwnProperty(_isReadonly);
+ }
+}
diff --git a/libraries/api-extractor-model/src/model/ApiConstructor.ts b/libraries/api-extractor-model/src/model/ApiConstructor.ts
index 51261d157da..c25a7e1e4a5 100644
--- a/libraries/api-extractor-model/src/model/ApiConstructor.ts
+++ b/libraries/api-extractor-model/src/model/ApiConstructor.ts
@@ -50,7 +50,7 @@ export interface IApiConstructorOptions
* @public
*/
export class ApiConstructor extends ApiParameterListMixin(
- ApiReleaseTagMixin(ApiProtectedMixin(ApiDeclaredItem))
+ ApiProtectedMixin(ApiReleaseTagMixin(ApiDeclaredItem))
) {
public constructor(options: IApiConstructorOptions) {
super(options);
diff --git a/libraries/api-extractor-model/src/model/ApiMethod.ts b/libraries/api-extractor-model/src/model/ApiMethod.ts
index d461ef67b1e..c5b71ae03a5 100644
--- a/libraries/api-extractor-model/src/model/ApiMethod.ts
+++ b/libraries/api-extractor-model/src/model/ApiMethod.ts
@@ -27,13 +27,13 @@ import { ApiOptionalMixin, IApiOptionalMixinOptions } from '../mixins/ApiOptiona
*/
export interface IApiMethodOptions
extends IApiNameMixinOptions,
- IApiTypeParameterListMixinOptions,
+ IApiOptionalMixinOptions,
IApiParameterListMixinOptions,
IApiProtectedMixinOptions,
IApiReleaseTagMixinOptions,
IApiReturnTypeMixinOptions,
IApiStaticMixinOptions,
- IApiOptionalMixinOptions,
+ IApiTypeParameterListMixinOptions,
IApiDeclaredItemOptions {}
/**
@@ -58,10 +58,10 @@ export interface IApiMethodOptions
* @public
*/
export class ApiMethod extends ApiNameMixin(
- ApiTypeParameterListMixin(
+ ApiOptionalMixin(
ApiParameterListMixin(
- ApiReleaseTagMixin(
- ApiReturnTypeMixin(ApiProtectedMixin(ApiStaticMixin(ApiOptionalMixin(ApiDeclaredItem))))
+ ApiProtectedMixin(
+ ApiReleaseTagMixin(ApiReturnTypeMixin(ApiStaticMixin(ApiTypeParameterListMixin(ApiDeclaredItem))))
)
)
)
diff --git a/libraries/api-extractor-model/src/model/ApiVariable.ts b/libraries/api-extractor-model/src/model/ApiVariable.ts
index 85cfef5e558..c476693dabb 100644
--- a/libraries/api-extractor-model/src/model/ApiVariable.ts
+++ b/libraries/api-extractor-model/src/model/ApiVariable.ts
@@ -10,6 +10,7 @@ import {
import { ApiItemKind } from '../items/ApiItem';
import { ApiDeclaredItem, IApiDeclaredItemOptions, IApiDeclaredItemJson } from '../items/ApiDeclaredItem';
import { ApiReleaseTagMixin, IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin';
+import { ApiReadonlyMixin, IApiReadonlyMixinOptions } from '../mixins/ApiReadonlyMixin';
import { IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin';
import { IExcerptTokenRange, Excerpt } from '../mixins/Excerpt';
import { DeserializerContext } from './DeserializerContext';
@@ -21,6 +22,7 @@ import { DeserializerContext } from './DeserializerContext';
export interface IApiVariableOptions
extends IApiNameMixinOptions,
IApiReleaseTagMixinOptions,
+ IApiReadonlyMixinOptions,
IApiDeclaredItemOptions {
variableTypeTokenRange: IExcerptTokenRange;
}
@@ -49,7 +51,7 @@ export interface IApiVariableJson extends IApiDeclaredItemJson {
*
* @public
*/
-export class ApiVariable extends ApiNameMixin(ApiReleaseTagMixin(ApiDeclaredItem)) {
+export class ApiVariable extends ApiNameMixin(ApiReleaseTagMixin(ApiReadonlyMixin(ApiDeclaredItem))) {
/**
* An {@link Excerpt} that describes the type of the variable.
*/
diff --git a/libraries/api-extractor-model/src/model/DeserializerContext.ts b/libraries/api-extractor-model/src/model/DeserializerContext.ts
index 12cd9e15514..07ea19ce36f 100644
--- a/libraries/api-extractor-model/src/model/DeserializerContext.ts
+++ b/libraries/api-extractor-model/src/model/DeserializerContext.ts
@@ -36,17 +36,20 @@ export enum ApiJsonSchemaVersion {
V_1004 = 1004,
/**
- * Add an `isOptional` field to `IApiParameterOptions` to track whether a function parameter is optional.
+ * Add an `isOptional` field to `Parameter` and `TypeParameter` to track whether a function parameter is optional.
*
* When loading older JSON files, the value defaults to `false`.
*/
V_1005 = 1005,
/**
- * Add an `isProtected` field to `IApiConstructorOptions`, `IApiPropertyOptions`, and `IApiMethodOptions` to
+ * Add an `isProtected` field to `ApiConstructor`, `ApiMethod`, and `ApiProperty` to
* track whether a class member has the `protected` modifier.
*
- * When loading older JSON files, the value defaults to `false`.
+ * Add an `isReadonly` field to `ApiProperty`, `ApiPropertySignature`, and `ApiVariable` to
+ * track whether the item is readonly.
+ *
+ * When loading older JSON files, the values default to `false`.
*/
V_1006 = 1006,