@sarj/eslint-plugin 19.2.0 → 19.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog.js +8 -5
- package/dist/{chunk-JBAPB4JX.js → chunk-6RX5RU75.js} +43 -122
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/catalog.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
publicDocumentation,
|
|
3
3
|
ruleSpec,
|
|
4
4
|
src_default
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6RX5RU75.js";
|
|
6
6
|
|
|
7
7
|
// src/docs/directive-disable-enable-pair.ts
|
|
8
8
|
var DIRECTIVE_DISABLE_ENABLE_PAIR_DOCUMENTATION = {
|
|
@@ -4259,22 +4259,25 @@ var PREFER_DEPENDENCY_INTERFACE_DOCUMENTATION = {
|
|
|
4259
4259
|
|
|
4260
4260
|
// src/docs/prefer-discriminated-union.ts
|
|
4261
4261
|
var PREFER_DISCRIMINATED_UNION_DOCUMENTATION = {
|
|
4262
|
-
summary: "
|
|
4262
|
+
summary: "Preserve producer-proven tag/payload and Boolean state relationships in return types.",
|
|
4263
4263
|
defaultLevel: "warning",
|
|
4264
4264
|
rationale: "A flat object with optional branch data loses the relationship between a tag and its payload. Callers cannot narrow to the required fields, and the type permits incomplete or contradictory combinations.",
|
|
4265
4265
|
remediation: "If the variants are mutually exclusive, represent each with a literal tag and its required payload. Preserve shared fields on every member, including payload value types and nullability. For a producer returning a subset of a broader wire contract, give the producer a precise domain return type after validation.",
|
|
4266
4266
|
category: "correctness",
|
|
4267
4267
|
autofix: "safe",
|
|
4268
4268
|
limitations: [
|
|
4269
|
-
"
|
|
4269
|
+
"Names, Boolean counts and optional-field counts never establish a finding. A producer's direct literal writes establish either tag-specific payload presence or a pair of required Boolean fields with two or three distinct combinations, with both fields varying. All four combinations, constant dimensions and expression-valued flags are excluded. At most eight Boolean fields are compared. Only one relationship is reported per contract; payload evidence takes precedence.",
|
|
4270
4270
|
"Producer analysis requires a finite literal tag, every declared tag syntactically witnessed, exhaustive simple return paths without literal constant conditions, plain object returns, and consistent optional-field presence for each tag. It resolves only unmerged local aliases/interfaces without inheritance or generics, and the built-in Promise around async returns. This is syntax-only evidence of field presence; explicit undefined, void and null payloads are skipped, while expression value types are not inferred. Dynamic returns, spreads, computed keys, accessors, loops and try statements are deliberately skipped.",
|
|
4271
4271
|
"A switch producer is supported only for a non-overloaded function declaration when its sole body statement switches on an unchanged direct string or number parameter, has unique same-kind literal labels and a default, and every nonempty case body is a sole object return or throw, optionally inside sole blocks. Empty labels may share the next terminating body; nested conditions, conditional returns, statement prefixes, breaks, other fallthrough, captured/closed inputs and switches under preceding control flow abstain. Broad parameter domains establish input witnesses for each label and the default; this does not infer branch-specific runtime effects or expression value types. Path visits, depth and returned objects are bounded conservatively.",
|
|
4272
|
-
"
|
|
4272
|
+
"These are refactoring advisories, not proven defects or proof that other writers cannot produce more states. Historical observations, partial results, unknown states and independently completing operations may need the broader contract. Review all readers and writers before migrating a shared contract; preserve every valid combination. A union of existing literal flag pairs is the smallest type-only replacement; a named disposition is a reviewed domain migration.",
|
|
4273
|
+
"Automatic fixes are limited to an unused private nongeneric synchronous function with a direct inline contract and one conditional return containing at most four literal objects. They narrow only the existing discriminator or implicated Boolean pair and preserve other member types and all runtime code, including condition evaluation, object creation, identity and exceptions. Nested conditionals are supported. Shared/observed contracts, aliases, exports, async functions, comments, expression payloads and generated/declaration/test files remain excluded. Public interfaces, serialization and cancellation are never rewritten."
|
|
4273
4274
|
],
|
|
4274
4275
|
references: ["https://functional-architecture.org/make_illegal_states_unrepresentable/", "https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions"],
|
|
4275
4276
|
examples: [
|
|
4276
4277
|
{ id: "explicit-result-branches", title: "Use explicit result branches", outcome: "no-match", files: [{ path: "src/result.ts", source: "type Result = { ok: true; data: string } | { ok: false; error: string };" }], focusPath: "src/result.ts", expectedCount: 0, public: true },
|
|
4277
|
-
{ id: "optional-result-payloads", title: "
|
|
4278
|
+
{ id: "optional-result-payloads", title: "A producer establishes the status-to-payload relationship", outcome: "match", files: [{ path: "src/result.ts", source: 'function result(ok: boolean): { ok: boolean; data?: string; error?: string } { return ok ? { ok: true, data: "value" } : { ok: false, error: "failed" }; }' }], focusPath: "src/result.ts", expectedCount: 1, public: true },
|
|
4279
|
+
{ id: "failure-dispositions", scenarioId: "boolean-state", title: "A producer returns retry, terminal and saved-partial combinations", outcome: "match", files: [{ path: "src/failure.ts", source: "function failure(retry: boolean, saved: boolean): { retriable: boolean; persisted: boolean } { return saved ? { retriable: false, persisted: true } : retry ? { retriable: true, persisted: false } : { retriable: false, persisted: false }; }" }], focusPath: "src/failure.ts", expectedCount: 1, public: true },
|
|
4280
|
+
{ id: "independent-observations", scenarioId: "boolean-state", title: "Independent observations retain all four combinations", outcome: "no-match", files: [{ path: "src/observations.ts", source: "function observations(a: boolean, b: boolean): { started: boolean; reported: boolean } { return a ? b ? { started: true, reported: true } : { started: true, reported: false } : b ? { started: false, reported: true } : { started: false, reported: false }; }" }], focusPath: "src/observations.ts", expectedCount: 0, public: true },
|
|
4278
4281
|
{ id: "flat-produced-variants", scenarioId: "produced-variants", title: "Preserve producer variant relationships", outcome: "match", files: [{ path: "src/job.ts", source: 'function job(done: boolean): { phase: "queued" | "complete"; ticket?: string } { return done ? { phase: "complete" } : { phase: "queued", ticket: "t" }; }' }], focusPath: "src/job.ts", expectedCount: 1, public: true },
|
|
4279
4282
|
{ id: "explicit-produced-variants", scenarioId: "produced-variants", title: "Give each produced variant its payload", outcome: "no-match", files: [{ path: "src/job.ts", source: 'function job(done: boolean): { phase: "queued"; ticket: string } | { phase: "complete" } { return done ? { phase: "complete" } : { phase: "queued", ticket: "t" }; }' }], focusPath: "src/job.ts", expectedCount: 0, public: true },
|
|
4280
4283
|
{ id: "flat-switch-producer", scenarioId: "switch-producer", title: "A complete dispatcher preserves each returned variant", outcome: "match", files: [{ path: "src/job.ts", source: 'function job(command: string): { phase: "queued" | "complete"; ticket?: string } { switch (command) { case "start": return { phase: "queued", ticket: "t" }; default: return { phase: "complete" }; } }' }], focusPath: "src/job.ts", expectedCount: 1, public: true },
|
|
@@ -22099,11 +22099,43 @@ function discriminatedUnionReturns(node, sourceCode2) {
|
|
|
22099
22099
|
if (member3.optional) continue;
|
|
22100
22100
|
const domain = tagDomain(member3.typeAnnotation?.typeAnnotation);
|
|
22101
22101
|
if (domain !== void 0 && hasTagSpecificPayload(name, domain, shape.optional, returned2)) {
|
|
22102
|
-
return { reportNode: contract.reportNode, tag: name, members: shape.members, returned: returned2 };
|
|
22102
|
+
return { reportNode: contract.reportNode, relationship: { kind: "presence", tag: name }, members: shape.members, returned: returned2 };
|
|
22103
|
+
}
|
|
22104
|
+
}
|
|
22105
|
+
const fields2 = correlatedBooleanFields(shape, returned2);
|
|
22106
|
+
return fields2 === void 0 ? void 0 : {
|
|
22107
|
+
reportNode: contract.reportNode,
|
|
22108
|
+
relationship: { kind: "boolean-pair", fields: fields2 },
|
|
22109
|
+
members: shape.members,
|
|
22110
|
+
returned: returned2
|
|
22111
|
+
};
|
|
22112
|
+
}
|
|
22113
|
+
function correlatedBooleanFields(shape, returned2) {
|
|
22114
|
+
const fields2 = [...shape.members].filter(([, member3]) => !member3.optional && member3.typeAnnotation?.typeAnnotation.type === "TSBooleanKeyword").map(([name]) => name);
|
|
22115
|
+
if (fields2.length > 8) return void 0;
|
|
22116
|
+
for (const [index, left] of fields2.entries()) {
|
|
22117
|
+
for (const right of fields2.slice(index + 1)) {
|
|
22118
|
+
const combinations = booleanCombinations(left, right, returned2);
|
|
22119
|
+
if (combinations !== void 0 && restrictedVaryingPair(combinations)) return { left, right };
|
|
22103
22120
|
}
|
|
22104
22121
|
}
|
|
22105
22122
|
return void 0;
|
|
22106
22123
|
}
|
|
22124
|
+
function booleanCombinations(left, right, returned2) {
|
|
22125
|
+
const combinations = /* @__PURE__ */ new Set();
|
|
22126
|
+
for (const properties2 of returned2) {
|
|
22127
|
+
const a = properties2.get(left);
|
|
22128
|
+
const b = properties2.get(right);
|
|
22129
|
+
if (a?.type !== "Literal" || typeof a.value !== "boolean" || b?.type !== "Literal" || typeof b.value !== "boolean") return void 0;
|
|
22130
|
+
combinations.add(`${Number(a.value)}${Number(b.value)}`);
|
|
22131
|
+
}
|
|
22132
|
+
return combinations;
|
|
22133
|
+
}
|
|
22134
|
+
function restrictedVaryingPair(combinations) {
|
|
22135
|
+
if (combinations.size < 2 || combinations.size === 4) return false;
|
|
22136
|
+
const values = [...combinations];
|
|
22137
|
+
return [0, 1].every((index) => values.some((value) => value[index] === "0") && values.some((value) => value[index] === "1"));
|
|
22138
|
+
}
|
|
22107
22139
|
function returnContract(node, sourceCode2) {
|
|
22108
22140
|
const annotation = node.returnType;
|
|
22109
22141
|
if (!isPresent(annotation)) return void 0;
|
|
@@ -22148,7 +22180,7 @@ function objectContract(elements) {
|
|
|
22148
22180
|
members2.set(name, member3);
|
|
22149
22181
|
if (member3.optional) optional.add(name);
|
|
22150
22182
|
}
|
|
22151
|
-
return
|
|
22183
|
+
return { members: members2, optional };
|
|
22152
22184
|
}
|
|
22153
22185
|
function returnedProperties(objects, contract) {
|
|
22154
22186
|
const returned2 = [];
|
|
@@ -22334,102 +22366,18 @@ function literalTag(node) {
|
|
|
22334
22366
|
|
|
22335
22367
|
// src/rules/prefer-discriminated-union.ts
|
|
22336
22368
|
var NAME94 = "prefer-discriminated-union";
|
|
22337
|
-
var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
22338
|
-
"success",
|
|
22339
|
-
"ok"
|
|
22340
|
-
]);
|
|
22341
|
-
var FAILURE_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
22342
|
-
"error",
|
|
22343
|
-
"errors",
|
|
22344
|
-
"reason",
|
|
22345
|
-
"cause"
|
|
22346
|
-
]);
|
|
22347
|
-
var SUCCESS_PAYLOAD_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
22348
|
-
"data",
|
|
22349
|
-
"events",
|
|
22350
|
-
"payload",
|
|
22351
|
-
"response",
|
|
22352
|
-
"result",
|
|
22353
|
-
"value"
|
|
22354
|
-
]);
|
|
22355
|
-
var REQUIRED_STATUS_MEMBER_COUNT = 1;
|
|
22356
|
-
var FUNCTION_RETURN_OWNER_TYPES = /* @__PURE__ */ new Set([
|
|
22357
|
-
"ArrowFunctionExpression",
|
|
22358
|
-
"FunctionDeclaration",
|
|
22359
|
-
"FunctionExpression",
|
|
22360
|
-
"TSDeclareFunction",
|
|
22361
|
-
"TSEmptyBodyFunctionExpression",
|
|
22362
|
-
"TSFunctionType",
|
|
22363
|
-
"TSMethodSignature"
|
|
22364
|
-
]);
|
|
22365
|
-
function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
22366
|
-
let statusMemberCount = 0;
|
|
22367
|
-
let hasFailurePayload = false;
|
|
22368
|
-
let hasSuccessPayload = false;
|
|
22369
|
-
let hasUnrecognizedMember = false;
|
|
22370
|
-
for (const member3 of typeLiteral.members) {
|
|
22371
|
-
if (member3.type !== "TSPropertySignature") {
|
|
22372
|
-
hasUnrecognizedMember = true;
|
|
22373
|
-
continue;
|
|
22374
|
-
}
|
|
22375
|
-
const name = getMemberName(member3);
|
|
22376
|
-
if (name !== null && STATUS_MEMBER_NAMES.has(name) && isBooleanTyped(member3) && !member3.optional) {
|
|
22377
|
-
statusMemberCount += 1;
|
|
22378
|
-
continue;
|
|
22379
|
-
}
|
|
22380
|
-
if (!member3.optional || isBooleanTyped(member3) || name === null) {
|
|
22381
|
-
hasUnrecognizedMember = true;
|
|
22382
|
-
continue;
|
|
22383
|
-
}
|
|
22384
|
-
if (FAILURE_MEMBER_NAMES.has(name)) {
|
|
22385
|
-
hasFailurePayload = true;
|
|
22386
|
-
} else if (SUCCESS_PAYLOAD_MEMBER_NAMES.has(name)) {
|
|
22387
|
-
hasSuccessPayload = true;
|
|
22388
|
-
} else {
|
|
22389
|
-
hasUnrecognizedMember = true;
|
|
22390
|
-
}
|
|
22391
|
-
}
|
|
22392
|
-
return statusMemberCount === REQUIRED_STATUS_MEMBER_COUNT && hasFailurePayload && (hasSuccessPayload || !hasUnrecognizedMember);
|
|
22393
|
-
}
|
|
22394
|
-
function getMemberName(member3) {
|
|
22395
|
-
if (member3.type !== "TSPropertySignature" || member3.computed) {
|
|
22396
|
-
return null;
|
|
22397
|
-
}
|
|
22398
|
-
const { key } = member3;
|
|
22399
|
-
if (key.type === "Identifier") {
|
|
22400
|
-
return key.name;
|
|
22401
|
-
}
|
|
22402
|
-
if (key.type === "Literal" && typeof key.value === "string") {
|
|
22403
|
-
return key.value;
|
|
22404
|
-
}
|
|
22405
|
-
return null;
|
|
22406
|
-
}
|
|
22407
|
-
function isBooleanTyped(member3) {
|
|
22408
|
-
return member3.typeAnnotation?.typeAnnotation.type === "TSBooleanKeyword";
|
|
22409
|
-
}
|
|
22410
|
-
function inlineReturnTypeLiteral(node) {
|
|
22411
|
-
let annotation = null;
|
|
22412
|
-
if (node.parent.type === "TSTypeAnnotation") {
|
|
22413
|
-
annotation = node.parent;
|
|
22414
|
-
} else if (node.parent.type === "TSTypeParameterInstantiation" && node.parent.params.length === 1 && node.parent.params[0] === node && node.parent.parent.type === "TSTypeReference" && node.parent.parent.typeName.type === "Identifier" && node.parent.parent.typeName.name === "Promise" && node.parent.parent.parent.type === "TSTypeAnnotation") {
|
|
22415
|
-
annotation = node.parent.parent.parent;
|
|
22416
|
-
}
|
|
22417
|
-
if (annotation === null) return null;
|
|
22418
|
-
const owner = annotation.parent;
|
|
22419
|
-
return FUNCTION_RETURN_OWNER_TYPES.has(owner.type) && "returnType" in owner && owner.returnType === annotation ? annotation : null;
|
|
22420
|
-
}
|
|
22421
22369
|
var prefer_discriminated_union_default = defineRule({
|
|
22422
22370
|
meta: {
|
|
22423
22371
|
type: "suggestion",
|
|
22424
22372
|
fixable: "code",
|
|
22425
22373
|
docs: {
|
|
22426
|
-
description: "
|
|
22374
|
+
description: "Preserve producer-proven tag/payload and Boolean state relationships in return types.",
|
|
22427
22375
|
url: docsUrl(NAME94)
|
|
22428
22376
|
},
|
|
22429
22377
|
schema: [],
|
|
22430
22378
|
messages: {
|
|
22431
22379
|
preferProducedVariants: "This producer returns tag-specific payloads for `{{tag}}`, but its flat return contract makes them optional. If these variants define the domain, use a discriminated union with each variant's required payload, or give this producer a precise return type separate from the broader contract.",
|
|
22432
|
-
|
|
22380
|
+
preferProducedState: "This producer returns a restricted set of literal combinations for `{{fields}}`, while its Boolean fields permit all four. Review a union preserving every returned combination, or a typed disposition if these are domain phases. Other writers and readers of a shared contract require review."
|
|
22433
22381
|
}
|
|
22434
22382
|
},
|
|
22435
22383
|
createOnce(context) {
|
|
@@ -22443,30 +22391,13 @@ var prefer_discriminated_union_default = defineRule({
|
|
|
22443
22391
|
if (result === void 0 || reportedContracts.has(result.reportNode)) return;
|
|
22444
22392
|
reportedContracts.add(result.reportNode);
|
|
22445
22393
|
const fix = privateVariantReturn(context.sourceCode, context.filename, node, result);
|
|
22394
|
+
const relationship = result.relationship;
|
|
22446
22395
|
context.report({
|
|
22447
22396
|
node: result.reportNode,
|
|
22448
|
-
messageId: "preferProducedVariants",
|
|
22449
22397
|
...fix !== null && { fix },
|
|
22450
|
-
data: { tag:
|
|
22398
|
+
...relationship.kind === "presence" ? { messageId: "preferProducedVariants", data: { tag: relationship.tag } } : { messageId: "preferProducedState", data: { fields: [relationship.fields.left, relationship.fields.right].join("`, `") } }
|
|
22451
22399
|
});
|
|
22452
22400
|
}
|
|
22453
|
-
function checkTypeLiteral(typeLiteral, reportNode) {
|
|
22454
|
-
if (looksLikeMutuallyExclusiveState(typeLiteral) && !reportedContracts.has(reportNode)) {
|
|
22455
|
-
reportedContracts.add(reportNode);
|
|
22456
|
-
const fix = inlineProducerFix(reportNode);
|
|
22457
|
-
context.report({
|
|
22458
|
-
node: reportNode,
|
|
22459
|
-
messageId: "preferDiscriminatedUnion",
|
|
22460
|
-
...fix !== null && { fix }
|
|
22461
|
-
});
|
|
22462
|
-
}
|
|
22463
|
-
}
|
|
22464
|
-
function inlineProducerFix(reportNode) {
|
|
22465
|
-
if (reportNode.type !== "TSTypeAnnotation" || reportNode.parent.type !== "FunctionDeclaration") return null;
|
|
22466
|
-
const owner = reportNode.parent;
|
|
22467
|
-
const result = discriminatedUnionReturns(owner, context.sourceCode);
|
|
22468
|
-
return result === void 0 ? null : privateVariantReturn(context.sourceCode, context.filename, owner, result);
|
|
22469
|
-
}
|
|
22470
22401
|
return {
|
|
22471
22402
|
before() {
|
|
22472
22403
|
reportedContracts.clear();
|
|
@@ -22480,34 +22411,23 @@ var prefer_discriminated_union_default = defineRule({
|
|
|
22480
22411
|
FunctionExpression: rememberProducer,
|
|
22481
22412
|
"Program:exit"() {
|
|
22482
22413
|
for (const producer of producers) checkProducer(producer);
|
|
22483
|
-
},
|
|
22484
|
-
TSInterfaceDeclaration(node) {
|
|
22485
|
-
if (node.extends.length > 0) {
|
|
22486
|
-
return;
|
|
22487
|
-
}
|
|
22488
|
-
checkTypeLiteral({ members: node.body.body }, node);
|
|
22489
|
-
},
|
|
22490
|
-
TSTypeLiteral(node) {
|
|
22491
|
-
if (node.parent.type === "TSTypeAliasDeclaration") checkTypeLiteral(node, node.parent);
|
|
22492
|
-
const annotation = inlineReturnTypeLiteral(node);
|
|
22493
|
-
if (annotation !== null) checkTypeLiteral(node, annotation);
|
|
22494
22414
|
}
|
|
22495
22415
|
};
|
|
22496
22416
|
}
|
|
22497
22417
|
});
|
|
22498
22418
|
function privateVariantReturn(sourceCode2, filename, owner, result) {
|
|
22499
22419
|
const annotation = owner.returnType?.typeAnnotation;
|
|
22500
|
-
if (owner.type !== "FunctionDeclaration" || owner.id === null || !returnsOnlyConditionalObject(owner) || annotation?.type !== "TSTypeLiteral" || result.reportNode !== owner.returnType || result.returned.length
|
|
22420
|
+
if (owner.type !== "FunctionDeclaration" || owner.id === null || !returnsOnlyConditionalObject(owner) || annotation?.type !== "TSTypeLiteral" || result.reportNode !== owner.returnType || result.returned.length > 4 || sourceCode2.getCommentsInside(owner).length > 0 || !isUnusedPrivateBinding(sourceCode2, owner, owner.id, filename) || !retainsNamedTypeUses(sourceCode2, annotation)) return null;
|
|
22501
22421
|
const variants2 = result.returned.map((properties2) => privateVariantType(properties2, result, sourceCode2));
|
|
22502
22422
|
if (variants2.some((variant) => variant === null)) return null;
|
|
22503
|
-
const text = `${variants2.join(" | ")}${sourceCode2.getText(annotation).replace(/[^\r\n]/gu, "")}`;
|
|
22423
|
+
const text = `${variants2.join(" | ")}${sourceCode2.getText(annotation).replace(/[^\r\n\u2028\u2029]/gu, "")}`;
|
|
22504
22424
|
return (fixer) => fixer.replaceText(annotation, text);
|
|
22505
22425
|
}
|
|
22506
22426
|
function returnsOnlyConditionalObject(fn) {
|
|
22507
22427
|
if (fn.async || fn.generator || isPresent(fn.typeParameters)) return false;
|
|
22508
22428
|
const statements = fn.body?.body ?? [];
|
|
22509
22429
|
const [returned2] = statements;
|
|
22510
|
-
return statements.length === 1 && returned2?.type === "ReturnStatement" && returned2.argument?.type === "ConditionalExpression"
|
|
22430
|
+
return statements.length === 1 && returned2?.type === "ReturnStatement" && returned2.argument?.type === "ConditionalExpression";
|
|
22511
22431
|
}
|
|
22512
22432
|
function privateVariantType(properties2, result, sourceCode2) {
|
|
22513
22433
|
if ([...properties2.values()].some((value) => value.type !== "Literal" || typeof value.value === "object" && value.value !== null || typeof value.value === "number" && !Number.isFinite(value.value))) return null;
|
|
@@ -22517,7 +22437,8 @@ function privateVariantType(properties2, result, sourceCode2) {
|
|
|
22517
22437
|
if (value === void 0) continue;
|
|
22518
22438
|
const annotation = member3.typeAnnotation?.typeAnnotation;
|
|
22519
22439
|
if (annotation === void 0) return null;
|
|
22520
|
-
const
|
|
22440
|
+
const narrow = result.relationship.kind === "presence" ? name === result.relationship.tag : name === result.relationship.fields.left || name === result.relationship.fields.right;
|
|
22441
|
+
const type = narrow ? sourceCode2.getText(value) : sourceCode2.getText(annotation);
|
|
22521
22442
|
fields2.push(`${member3.readonly ? "readonly " : ""}${sourceCode2.getText(member3.key)}: ${type}`);
|
|
22522
22443
|
}
|
|
22523
22444
|
return `{ ${fields2.join("; ")} }`;
|
package/dist/index.js
CHANGED