@openpkg-ts/sdk 0.54.11 → 0.55.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/browser.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  toPagefindRecords,
22
22
  toSearchIndex,
23
23
  toSearchIndexJSON
24
- } from "./shared/chunk-7287tqkx.js";
24
+ } from "./shared/chunk-pwvdnach.js";
25
25
  // src/core/spec-converters.ts
26
26
  function getLangForHighlight(lang) {
27
27
  const langMap = {
package/dist/index.d.ts CHANGED
@@ -1333,7 +1333,7 @@ declare function getJSDocComment(node: ts4.Node, symbol?: ts4.Symbol, checker?:
1333
1333
  };
1334
1334
  declare function getSourceLocation(node: ts4.Node, sourceFile: ts4.SourceFile): SpecSource;
1335
1335
  /**
1336
- * Get description for a destructured parameter property from JSDoc @param tags.
1336
+ * Get description for a parameter or destructured key from JSDoc @param tags.
1337
1337
  * Matches patterns like:
1338
1338
  * - @param paramName - exact match
1339
1339
  * - @param opts.paramName - dotted notation with alias
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  toPagefindRecords,
26
26
  toSearchIndex,
27
27
  toSearchIndexJSON
28
- } from "./shared/chunk-7287tqkx.js";
28
+ } from "./shared/chunk-pwvdnach.js";
29
29
 
30
30
  // src/primitives/diff.ts
31
31
  import {
@@ -2111,17 +2111,41 @@ function getSourceLocation(node, sourceFile) {
2111
2111
  line: line + 1
2112
2112
  };
2113
2113
  }
2114
+ function bindingPatternKind(decl) {
2115
+ if (!decl)
2116
+ return;
2117
+ if (ts2.isObjectBindingPattern(decl.name))
2118
+ return "object";
2119
+ if (ts2.isArrayBindingPattern(decl.name))
2120
+ return "array";
2121
+ return;
2122
+ }
2123
+ function destructuredParamName(kind, taken, jsdocName) {
2124
+ if (jsdocName && !taken.has(jsdocName))
2125
+ return jsdocName;
2126
+ const base = kind === "object" ? "options" : "args";
2127
+ if (!taken.has(base))
2128
+ return base;
2129
+ let i = 2;
2130
+ while (taken.has(`${base}${i}`))
2131
+ i++;
2132
+ return `${base}${i}`;
2133
+ }
2134
+ function jsdocParamTagName(tag) {
2135
+ if (tag.tagName.text !== "param")
2136
+ return "";
2137
+ const paramTag = tag;
2138
+ try {
2139
+ return paramTag.name?.getText() ?? "";
2140
+ } catch {
2141
+ return paramTag.name?.text ?? "";
2142
+ }
2143
+ }
2114
2144
  function getParamDescription(propertyName, jsdocTags, inferredAlias) {
2115
2145
  for (const tag of jsdocTags) {
2116
2146
  if (tag.tagName.text !== "param")
2117
2147
  continue;
2118
- const paramTag = tag;
2119
- let tagParamName = "";
2120
- try {
2121
- tagParamName = paramTag.name?.getText() ?? "";
2122
- } catch {
2123
- tagParamName = paramTag.name?.text ?? "";
2124
- }
2148
+ const tagParamName = jsdocParamTagName(tag);
2125
2149
  const isMatch = tagParamName === propertyName || inferredAlias && tagParamName === `${inferredAlias}.${propertyName}` || tagParamName.endsWith(`.${propertyName}`);
2126
2150
  if (isMatch) {
2127
2151
  const comment = typeof tag.comment === "string" ? tag.comment : ts2.getTextOfJSDocComment(tag.comment);
@@ -3893,6 +3917,7 @@ function buildSchemaInternal(type, checker, ctx, typeNode) {
3893
3917
  function buildFunctionSchema(callSignatures, checker, ctx) {
3894
3918
  const buildSignatures = () => {
3895
3919
  const signatures = callSignatures.map((sig) => {
3920
+ const taken = new Set(sig.getParameters().filter((p) => !bindingPatternKind(p.valueDeclaration)).map((p) => p.getName()));
3896
3921
  const params = sig.getParameters().flatMap((param) => {
3897
3922
  const decl = param.valueDeclaration;
3898
3923
  if (!decl)
@@ -3900,11 +3925,18 @@ function buildFunctionSchema(callSignatures, checker, ctx) {
3900
3925
  const paramType = checker.getTypeOfSymbolAtLocation(param, decl);
3901
3926
  const isOptional = !!decl?.questionToken || !!decl?.initializer;
3902
3927
  const effectiveType = isOptional ? stripUndefinedFromType(paramType, checker) : paramType;
3928
+ const pattern = bindingPatternKind(decl);
3929
+ let name = param.getName();
3930
+ if (pattern) {
3931
+ name = destructuredParamName(pattern, taken);
3932
+ taken.add(name);
3933
+ }
3903
3934
  return {
3904
- name: param.getName(),
3935
+ name,
3905
3936
  schema: buildSchema(effectiveType, checker, ctx, decl.type),
3906
3937
  required: !isOptional && !decl.dotDotDotToken,
3907
- ...decl.dotDotDotToken ? { rest: true } : {}
3938
+ ...decl.dotDotDotToken ? { rest: true } : {},
3939
+ ...pattern ? { "x-ts-destructured": true } : {}
3908
3940
  };
3909
3941
  });
3910
3942
  const returnType = checker.getReturnTypeOfSignature(sig);
@@ -4505,121 +4537,185 @@ function extractParameters(signature, ctx) {
4505
4537
  const result = [];
4506
4538
  const signatureDecl = signature.getDeclaration();
4507
4539
  const jsdocTags = signatureDecl ? ts7.getJSDocTags(signatureDecl) : [];
4540
+ const names = destructuredNames(signature.getParameters(), jsdocTags, checker);
4508
4541
  for (const param of signature.getParameters()) {
4509
4542
  const decl = param.valueDeclaration;
4510
4543
  if (!decl)
4511
4544
  continue;
4512
4545
  const defer = typeNodeDefersExpansion(decl.type, checker, ctx.program);
4513
4546
  const type = defer ? undefined : checker.getTypeOfSymbolAtLocation(param, decl);
4514
- if (decl && ts7.isObjectBindingPattern(decl.name)) {
4515
- const expandedParams = expandBindingPattern(decl, type ?? checker.getTypeOfSymbolAtLocation(param, decl), jsdocTags, ctx);
4516
- result.push(...expandedParams);
4517
- } else {
4518
- const isOptional = !!decl?.questionToken || !!decl?.initializer;
4519
- const isRest = !!decl.dotDotDotToken;
4520
- const paramName = param.getName();
4521
- const description = getParamDescription(paramName, jsdocTags);
4522
- const schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
4523
- if (!defer && type) {
4524
- registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
4525
- }
4526
- const paramResult = {
4527
- name: paramName,
4528
- schema,
4529
- required: !isOptional && !isRest,
4530
- ...isRest ? { rest: true } : {}
4531
- };
4532
- if (description) {
4533
- paramResult.description = description;
4534
- const inlineTags = parseInlineTags(description);
4535
- if (inlineTags)
4536
- paramResult.inlineTags = inlineTags;
4537
- }
4538
- if (decl.initializer) {
4539
- applyDefault(paramResult, decl.initializer);
4540
- }
4541
- result.push(paramResult);
4542
- }
4543
- }
4544
- return result;
4545
- }
4546
- function expandBindingPattern(paramDecl, paramType, jsdocTags, ctx) {
4547
- const { typeChecker: checker } = ctx;
4548
- const result = [];
4549
- const bindingPattern = paramDecl.name;
4550
- const allProperties = getEffectiveProperties(paramType, checker);
4551
- const inferredAlias = inferParamAlias(jsdocTags);
4552
- for (const element of bindingPattern.elements) {
4553
- if (!ts7.isBindingElement(element))
4554
- continue;
4555
- const propertyName = element.propertyName ? ts7.isIdentifier(element.propertyName) ? element.propertyName.text : element.propertyName.getText() : ts7.isIdentifier(element.name) ? element.name.text : element.name.getText();
4556
- const propSymbol = allProperties.get(propertyName);
4557
- if (!propSymbol)
4558
- continue;
4559
- const isOptional = !!(propSymbol.flags & ts7.SymbolFlags.Optional) || element.initializer !== undefined;
4560
- const propType = checker.getTypeOfSymbol(propSymbol);
4561
- const effectiveType = isOptional ? stripUndefinedFromType(propType, checker) : propType;
4562
- registerReferencedTypes(effectiveType, ctx);
4563
- const description = getParamDescription(propertyName, jsdocTags, inferredAlias);
4564
- const param = {
4565
- name: propertyName,
4566
- schema: buildSchema(effectiveType, checker, ctx, declaredTypeNode(propSymbol.valueDeclaration)),
4567
- required: !isOptional
4547
+ const isOptional = !!decl.questionToken || !!decl.initializer;
4548
+ const isRest = !!decl.dotDotDotToken;
4549
+ const pattern = bindingPatternKind(decl);
4550
+ const paramName = pattern ? names.get(param) ?? param.getName() : param.getName();
4551
+ const description = getParamDescription(paramName, jsdocTags);
4552
+ let schema = defer ? buildSchemaFromTypeNode(decl.type, checker, ctx) : buildSchema(isOptional ? stripUndefinedFromType(type, checker) : type, checker, ctx, decl.type);
4553
+ if (!defer && type) {
4554
+ registerReferencedTypes(isOptional ? stripUndefinedFromType(type, checker) : type, ctx);
4555
+ }
4556
+ if (pattern === "object") {
4557
+ schema = resolvedObjectSchema(schema, param, decl, isOptional, ctx);
4558
+ }
4559
+ const paramResult = {
4560
+ name: paramName,
4561
+ schema,
4562
+ required: !isOptional && !isRest,
4563
+ ...isRest ? { rest: true } : {},
4564
+ ...pattern ? { "x-ts-destructured": true } : {}
4568
4565
  };
4569
4566
  if (description) {
4570
- param.description = description;
4567
+ paramResult.description = description;
4571
4568
  const inlineTags = parseInlineTags(description);
4572
4569
  if (inlineTags)
4573
- param.inlineTags = inlineTags;
4570
+ paramResult.inlineTags = inlineTags;
4574
4571
  }
4575
- if (element.initializer) {
4576
- applyDefault(param, element.initializer);
4572
+ if (decl.initializer) {
4573
+ applyDefault(paramResult, decl.initializer);
4574
+ }
4575
+ if (pattern === "object") {
4576
+ annotateBindingElements(decl.name, paramResult, jsdocTags);
4577
4577
  }
4578
- result.push(param);
4578
+ result.push(paramResult);
4579
4579
  }
4580
4580
  return result;
4581
4581
  }
4582
- function getEffectiveProperties(type, _checker) {
4583
- const properties = new Map;
4584
- if (type.isIntersection()) {
4585
- for (const subType of type.types) {
4586
- for (const prop of subType.getProperties()) {
4587
- properties.set(prop.getName(), prop);
4588
- }
4582
+ function destructuredNames(params, jsdocTags, checker) {
4583
+ const names = new Map;
4584
+ const taken = new Set;
4585
+ const patterns = [];
4586
+ for (const param of params) {
4587
+ const decl = param.valueDeclaration;
4588
+ const kind = bindingPatternKind(decl);
4589
+ if (!kind || !decl) {
4590
+ taken.add(param.getName());
4591
+ continue;
4589
4592
  }
4590
- } else {
4591
- for (const prop of type.getProperties()) {
4592
- properties.set(prop.getName(), prop);
4593
+ patterns.push({ symbol: param, decl, kind });
4594
+ }
4595
+ if (patterns.length === 0)
4596
+ return names;
4597
+ const tagNames = jsdocTags.map(jsdocParamTagName).filter((n) => n && !n.startsWith("__"));
4598
+ if (tagNames.length === 0) {
4599
+ for (const { symbol, kind } of patterns) {
4600
+ const name = destructuredParamName(kind, taken);
4601
+ taken.add(name);
4602
+ names.set(symbol, name);
4593
4603
  }
4604
+ return names;
4594
4605
  }
4595
- return properties;
4596
- }
4597
- function inferParamAlias(jsdocTags) {
4598
- const prefixes = [];
4599
- for (const tag of jsdocTags) {
4600
- if (tag.tagName.text !== "param")
4606
+ const keys = new Set;
4607
+ for (const { symbol, decl } of patterns) {
4608
+ for (const element of decl.name.elements) {
4609
+ const key = bindingElementKey(element);
4610
+ if (key)
4611
+ keys.add(key);
4612
+ }
4613
+ const type = checker.getTypeOfSymbolAtLocation(symbol, decl);
4614
+ for (const prop of resolvedProperties(type, checker))
4615
+ keys.add(prop.getName());
4616
+ }
4617
+ const candidates = [];
4618
+ for (const tagName of tagNames) {
4619
+ const [head, ...rest] = tagName.split(".");
4620
+ if (taken.has(head))
4601
4621
  continue;
4602
- const tagText = typeof tag.comment === "string" ? tag.comment : ts7.getTextOfJSDocComment(tag.comment) ?? "";
4603
- const paramTag = tag;
4604
- const paramName = paramTag.name?.getText() ?? "";
4605
- if (paramName.includes(".")) {
4606
- const prefix = paramName.split(".")[0];
4607
- if (prefix && !prefix.startsWith("__")) {
4608
- prefixes.push(prefix);
4609
- }
4610
- } else if (tagText.includes(".")) {
4611
- const match = tagText.match(/^(\w+)\./);
4612
- if (match && !match[1].startsWith("__")) {
4613
- prefixes.push(match[1]);
4614
- }
4622
+ if (rest.length === 0 && keys.has(head))
4623
+ continue;
4624
+ if (!candidates.includes(head))
4625
+ candidates.push(head);
4626
+ }
4627
+ patterns.forEach(({ symbol, kind }, i) => {
4628
+ const name = destructuredParamName(kind, taken, candidates[i]);
4629
+ taken.add(name);
4630
+ names.set(symbol, name);
4631
+ });
4632
+ return names;
4633
+ }
4634
+ function bindingElementKey(element) {
4635
+ if (!ts7.isBindingElement(element) || element.dotDotDotToken)
4636
+ return;
4637
+ const key = element.propertyName ?? element.name;
4638
+ if (ts7.isIdentifier(key))
4639
+ return key.text;
4640
+ if (ts7.isStringLiteral(key) || ts7.isNumericLiteral(key))
4641
+ return key.text;
4642
+ return;
4643
+ }
4644
+ function resolvedProperties(type, checker) {
4645
+ const seen = new Map;
4646
+ for (const arm of objectArms(type, checker)) {
4647
+ for (const prop of armProperties(arm, checker)) {
4648
+ if (!seen.has(prop.getName()))
4649
+ seen.set(prop.getName(), prop);
4615
4650
  }
4616
4651
  }
4617
- if (prefixes.length === 0)
4652
+ return [...seen.values()];
4653
+ }
4654
+ var PRIMITIVE_LIKE = ts7.TypeFlags.StringLike | ts7.TypeFlags.NumberLike | ts7.TypeFlags.BigIntLike | ts7.TypeFlags.BooleanLike | ts7.TypeFlags.ESSymbolLike | ts7.TypeFlags.Void | ts7.TypeFlags.Undefined | ts7.TypeFlags.Null;
4655
+ function objectArms(type, checker) {
4656
+ const arms = type.isUnion() ? type.types : [type];
4657
+ return arms.filter((arm) => !(arm.flags & PRIMITIVE_LIKE) && armProperties(arm, checker).length > 0);
4658
+ }
4659
+ function armProperties(arm, checker) {
4660
+ const own = checker.getPropertiesOfType(arm);
4661
+ return own.length > 0 ? own : checker.getPropertiesOfType(checker.getApparentType(arm));
4662
+ }
4663
+ function resolvedObjectSchema(schema, param, decl, isOptional, ctx) {
4664
+ if (typeof schema !== "object" || schema === null || Array.isArray(schema))
4665
+ return schema;
4666
+ const current = schema;
4667
+ if (current.properties || current.$ref)
4668
+ return schema;
4669
+ const { typeChecker: checker } = ctx;
4670
+ const raw = checker.getTypeOfSymbolAtLocation(param, decl);
4671
+ const type = isOptional ? stripUndefinedFromType(raw, checker) : raw;
4672
+ const arms = objectArms(type, checker);
4673
+ if (arms.length === 0)
4674
+ return schema;
4675
+ const props = resolvedProperties(type, checker);
4676
+ const resolved = buildObjectSchema(props, checker, ctx, type);
4677
+ if (arms.length > 1) {
4678
+ const requiredInAll = new Set(props.map((p) => p.getName()));
4679
+ for (const arm of arms) {
4680
+ const armRequired = new Set(armProperties(arm, checker).filter((p) => !(p.flags & ts7.SymbolFlags.Optional)).map((p) => p.getName()));
4681
+ for (const name of [...requiredInAll])
4682
+ if (!armRequired.has(name))
4683
+ requiredInAll.delete(name);
4684
+ }
4685
+ const required = resolved.required?.filter((n) => requiredInAll.has(n));
4686
+ if (required?.length)
4687
+ resolved.required = required;
4688
+ else
4689
+ delete resolved.required;
4690
+ }
4691
+ resolved["x-ts-type"] = renderTypeText(type, checker, decl);
4692
+ return resolved;
4693
+ }
4694
+ function annotateBindingElements(pattern, param, jsdocTags) {
4695
+ const schema = param.schema;
4696
+ const properties = schema?.properties;
4697
+ if (!properties)
4618
4698
  return;
4619
- const counts = new Map;
4620
- for (const p of prefixes)
4621
- counts.set(p, (counts.get(p) ?? 0) + 1);
4622
- return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0];
4699
+ for (const element of pattern.elements) {
4700
+ const propertyName = bindingElementKey(element);
4701
+ if (!propertyName)
4702
+ continue;
4703
+ const prop = properties[propertyName];
4704
+ if (!prop || typeof prop !== "object" || Array.isArray(prop))
4705
+ continue;
4706
+ const propSchema = prop;
4707
+ const description = getParamDescription(propertyName, jsdocTags, param.name);
4708
+ if (description && propSchema.description === undefined) {
4709
+ propSchema.description = description;
4710
+ }
4711
+ if (element.initializer) {
4712
+ const extracted = extractLiteralDefault(element.initializer);
4713
+ if (extracted.literal)
4714
+ propSchema.default = extracted.value;
4715
+ else
4716
+ propSchema["x-ts-default"] = extracted.text;
4717
+ }
4718
+ }
4623
4719
  }
4624
4720
  function extractLiteralDefault(initializer) {
4625
4721
  if (ts7.isStringLiteral(initializer)) {
@@ -6189,7 +6285,8 @@ function normalizeSignature(signature, options) {
6189
6285
  ...param.required !== undefined ? { required: param.required } : {},
6190
6286
  ...param.description ? { description: param.description } : {},
6191
6287
  ...param.default !== undefined ? { default: param.default } : {},
6192
- ...param.rest ? { rest: param.rest } : {}
6288
+ ...param.rest ? { rest: param.rest } : {},
6289
+ ...param["x-ts-destructured"] ? { "x-ts-destructured": true } : {}
6193
6290
  }));
6194
6291
  }
6195
6292
  if (signature.returns) {
@@ -97,7 +97,8 @@ function formatSchema(schema, options) {
97
97
  }
98
98
  if ("type" in schema && schema.type === "object") {
99
99
  if ("properties" in schema && schema.properties) {
100
- const props = Object.entries(schema.properties).map(([k, v]) => `${k}: ${formatSchema(v, nextOpts)}`).join("; ");
100
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
101
+ const props = Object.entries(schema.properties).map(([k, v]) => `${k}${required.has(k) ? "" : "?"}: ${formatSchema(v, nextOpts)}`).join("; ");
101
102
  return `{ ${props} }`;
102
103
  }
103
104
  return "object";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpkg-ts/sdk",
3
- "version": "0.54.11",
3
+ "version": "0.55.0",
4
4
  "description": "TypeScript API extraction SDK - programmatic primitives for OpenPkg specs",
5
5
  "keywords": [
6
6
  "openpkg",
@@ -43,7 +43,7 @@
43
43
  "test": "bun test"
44
44
  },
45
45
  "dependencies": {
46
- "@openpkg-ts/spec": "^0.54.9",
46
+ "@openpkg-ts/spec": "^0.55.0",
47
47
  "picomatch": "4.0.3",
48
48
  "typescript": "^5.0.0 || ^6.0.0"
49
49
  },