|
| 1 | +[](https://github.com/datocms/js-rest-api-clients/actions/workflows/node.js.yml) |
| 2 | + |
| 3 | +# DatoCMS CMA Client Analysis |
| 4 | + |
| 5 | +Static-analysis utilities for `@datocms/cma-client-node`, built on the TypeScript Compiler API. Inspects the `Client` class to extract method signatures, resolve referenced types, and produce ready-to-render TypeScript snippets — useful for generating API reference docs, AI tooling, or any introspection of the CMA client surface. |
| 6 | + |
| 7 | +## Installation |
| 8 | + |
| 9 | +```bash |
| 10 | +npm install @datocms/cma-client-analysis @datocms/cma-client-node @datocms/rest-api-reference typescript |
| 11 | +``` |
| 12 | + |
| 13 | +`@datocms/cma-client-node`, `@datocms/rest-api-reference`, and `typescript` are peer dependencies — the package introspects whichever versions of them are installed in your tree, so the output is always in sync with the client you actually run. |
| 14 | + |
| 15 | +## Usage |
| 16 | + |
| 17 | +```typescript |
| 18 | +import { |
| 19 | + getCmaClientProgram, |
| 20 | + extractAllMethodNames, |
| 21 | + extractMethodSignature, |
| 22 | + extractResourcesEndpointMethods, |
| 23 | + extractTypeDependencies, |
| 24 | +} from '@datocms/cma-client-analysis'; |
| 25 | + |
| 26 | +// Build a TypeScript program over @datocms/cma-client-node's .d.ts entry. |
| 27 | +// Expensive (~hundreds of ms): build once, thread through every extract* call. |
| 28 | +const { program, checker, clientClass } = getCmaClientProgram(); |
| 29 | + |
| 30 | +// All method names available on a resource. |
| 31 | +extractAllMethodNames(checker, clientClass, 'items'); |
| 32 | +// → ['list', 'find', 'create', 'rawList', 'rawFind', 'rawCreate', ...] |
| 33 | + |
| 34 | +// Full signature for one method, including referenced type symbols. |
| 35 | +const signature = extractMethodSignature(checker, clientClass, 'items', 'create'); |
| 36 | +// → { methodName, parameters, returnType, referencedTypeSymbols, ... } |
| 37 | + |
| 38 | +// All client methods that implement a given REST endpoint, matched by docUrl. |
| 39 | +import { findResourcesEntityByNamespace, findResourcesEndpointByRel, parseResourcesSchema } from '@datocms/rest-api-reference'; |
| 40 | +import resourcesJson from '@datocms/cma-client/resources.json'; |
| 41 | + |
| 42 | +const resourcesSchema = parseResourcesSchema(resourcesJson); |
| 43 | +const entity = findResourcesEntityByNamespace(resourcesSchema, 'menuItems'); |
| 44 | +const endpoint = findResourcesEndpointByRel(entity!, 'create'); |
| 45 | + |
| 46 | +const methods = extractResourcesEndpointMethods(checker, clientClass, endpoint!); |
| 47 | +// → [ |
| 48 | +// { name: 'create', functionDefinition: 'create(body: MenuItemCreateSchema): Promise<MenuItem>', referencedTypes: Set { ... } }, |
| 49 | +// { name: 'rawCreate', functionDefinition: 'rawCreate(body: MenuItemCreateSchema): Promise<MenuItemCreateTargetSchema>', referencedTypes: Set { ... } }, |
| 50 | +// ] |
| 51 | + |
| 52 | +// Inline TypeScript declarations for a set of referenced types, walking up to a depth. |
| 53 | +const { expandedTypes, notExpandedTypes } = extractTypeDependencies( |
| 54 | + checker, |
| 55 | + program, |
| 56 | + Array.from(signature!.referencedTypeSymbols.keys()), |
| 57 | + signature!.referencedTypeSymbols, |
| 58 | + { maxDepth: 2 }, |
| 59 | +); |
| 60 | +``` |
| 61 | + |
| 62 | +## Caching |
| 63 | + |
| 64 | +`getCmaClientProgram()` is *not* cached — every call rebuilds the program. The cost (parsing the full client `.d.ts` graph) is non-trivial, so: |
| 65 | + |
| 66 | +- **One-shot processes** (CLIs, scripts): call once at startup, thread the result through. |
| 67 | +- **Long-running processes** (servers, MCP): wrap the call in your own memoization. |
| 68 | + |
| 69 | +This keeps the lifetime decision in the consumer's hands instead of pinning it to module-level state. |
0 commit comments