Skip to content

Commit

Permalink
mark const object properties as readonly
Browse files Browse the repository at this point in the history
  • Loading branch information
souporserious committed Jul 10, 2024
1 parent d4eef53 commit 54bbe71
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 17 deletions.
6 changes: 3 additions & 3 deletions packages/utils/src/types/getTypeDocumentation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2110,23 +2110,23 @@ describe('getTypeDocumentation', () => {
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "String",
"name": "primary",
"type": ""#ff0000"",
},
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "String",
"name": "secondary",
"type": ""#00ff00"",
},
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "String",
"name": "tertiary",
"type": ""#0000ff"",
Expand Down
20 changes: 17 additions & 3 deletions packages/utils/src/types/getTypeDocumentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import type {
ClassDeclaration,
VariableDeclaration,
} from 'ts-morph'
import { Node, TypeFormatFlags } from 'ts-morph'
import {
Node,
SyntaxKind,
TypeFormatFlags,
VariableDeclarationKind,
} from 'ts-morph'

import { getJsDocMetadata } from '../js-docs'
import {
Expand Down Expand Up @@ -132,6 +137,12 @@ export function getTypeDocumentation(
}

if (Node.isVariableDeclaration(declaration)) {
const variableStatement = declaration.getFirstAncestorByKind(
SyntaxKind.VariableStatement
)
const isConst = variableStatement
? variableStatement.getDeclarationKind() === VariableDeclarationKind.Const
: false
const initializer = declaration.getInitializer()

if (
Expand All @@ -143,7 +154,8 @@ export function getTypeDocumentation(
const processedType = processType(
initializer.getType(),
declaration,
filter
filter,
isConst
)

if (!processedType) {
Expand All @@ -164,10 +176,12 @@ export function getTypeDocumentation(
}

if (Node.isAsExpression(initializer)) {
const typeNode = initializer.getTypeNode()
const processedType = processType(
initializer.getType(),
declaration,
filter
filter,
typeNode?.getText() === 'const'
)

if (processedType) {
Expand Down
19 changes: 10 additions & 9 deletions packages/utils/src/types/processType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,26 +719,27 @@ describe('processProperties', () => {
{ overwrite: true }
)
const variableDeclaration = sourceFile.getVariableDeclarationOrThrow('a')
const processedProperties = processType(variableDeclaration.getType())

// TODO: const properties should be marked as readonly
const processedProperties = processType(
variableDeclaration.getType(),
variableDeclaration
)

expect(processedProperties).toMatchInlineSnapshot(`
{
"kind": "Object",
"name": undefined,
"name": "a",
"properties": [
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "Object",
"name": "e",
"properties": [
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "Number",
"name": "f",
"type": "number",
Expand All @@ -749,23 +750,23 @@ describe('processProperties', () => {
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "String",
"name": "g",
"type": "string",
},
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "Number",
"name": "b",
"type": "1",
},
{
"defaultValue": undefined,
"isOptional": false,
"isReadonly": false,
"isReadonly": true,
"kind": "String",
"name": "c",
"type": ""string"",
Expand Down
27 changes: 25 additions & 2 deletions packages/utils/src/types/processType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Type,
TypeFormatFlags,
SyntaxKind,
VariableDeclarationKind,
type ClassDeclaration,
type FunctionDeclaration,
type ParameterDeclaration,
Expand Down Expand Up @@ -235,6 +236,7 @@ export function processType(
type: Type,
enclosingNode?: Node,
filter: SymbolFilter = defaultFilter,
isConst: boolean = false,
references: Set<string> = new Set(),
isRootType: boolean = true,
defaultValues?: Record<string, unknown> | unknown
Expand All @@ -247,6 +249,15 @@ export function processType(
symbol = apparentType.getAliasSymbol() || apparentType.getSymbol()
}

if (isConst === false && Node.isVariableDeclaration(enclosingNode)) {
const variableStatement = enclosingNode.getFirstAncestorByKind(
SyntaxKind.VariableStatement
)
isConst = variableStatement
? variableStatement.getDeclarationKind() === VariableDeclarationKind.Const
: false
}

const symbolMetadata = getSymbolMetadata(symbol, enclosingNode)
const symbolDeclaration = symbol?.getDeclarations().at(0)
const declaration = symbolDeclaration || enclosingNode
Expand Down Expand Up @@ -282,7 +293,7 @@ export function processType(
if (isUtilityType) {
const processedTypeArguments = aliasTypeArguments
.map((type) =>
processType(type, declaration, filter, references, false)
processType(type, declaration, filter, isConst, references, false)
)
.filter(Boolean) as ProcessedType[]

Expand Down Expand Up @@ -379,6 +390,7 @@ export function processType(
elementType,
declaration,
filter,
isConst,
references,
false
)
Expand Down Expand Up @@ -425,6 +437,7 @@ export function processType(
unionType,
declaration,
filter,
isConst,
references,
false,
defaultValues
Expand Down Expand Up @@ -464,6 +477,7 @@ export function processType(
intersectionType,
declaration,
filter,
isConst,
references,
false,
defaultValues
Expand Down Expand Up @@ -508,6 +522,7 @@ export function processType(
type,
declaration,
filter,
isConst,
references,
false
)
Expand Down Expand Up @@ -573,6 +588,7 @@ export function processType(
type,
declaration,
filter,
isConst,
references,
false,
defaultValues
Expand All @@ -585,6 +601,7 @@ export function processType(
type,
declaration,
filter,
isConst,
references,
false,
defaultValues
Expand Down Expand Up @@ -621,6 +638,7 @@ export function processType(
apparentType,
declaration,
filter,
isConst,
references,
false,
defaultValues
Expand Down Expand Up @@ -686,6 +704,7 @@ export function processSignature(
parameter.getTypeAtLocation(signatureDeclaration),
enclosingNode,
filter,
false,
references,
isRootType,
defaultValue
Expand Down Expand Up @@ -762,6 +781,7 @@ export function processTypeProperties(
type: Type,
enclosingNode?: Node,
filter: SymbolFilter = defaultFilter,
isConst: boolean = false,
references: Set<string> = new Set(),
isRootType: boolean = true,
defaultValues?: Record<string, unknown> | unknown
Expand Down Expand Up @@ -797,6 +817,7 @@ export function processTypeProperties(
propertyType,
declaration,
filter,
isConst,
references,
isRootType,
defaultValue
Expand All @@ -818,7 +839,7 @@ export function processTypeProperties(
name,
defaultValue,
isOptional,
isReadonly,
isReadonly: isConst || isReadonly,
} satisfies PropertyTypes
}
} else {
Expand All @@ -835,6 +856,7 @@ function processTypeTupleElements(
type: Type,
enclosingNode?: Node,
filter?: SymbolFilter,
isConst: boolean = false,
references: Set<string> = new Set(),
isRootType: boolean = true
) {
Expand All @@ -853,6 +875,7 @@ function processTypeTupleElements(
tupleElementType,
enclosingNode,
filter,
isConst,
references,
isRootType
)
Expand Down

0 comments on commit 54bbe71

Please sign in to comment.