or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis-metrics.mdapi-definition-reduction.mdextensions-customization.mdindex.mdopenapi-definition-management.mdoperation-discovery-analysis.mdparameter-handling-json-schema.mdrequest-response-management.mdschema-dereferencing-references.mdsecurity-authentication.mdserver-url-management.mdutils.md

analysis-metrics.mddocs/

0

# Analysis and Metrics

1

2

API definition analysis, feature detection, and complexity measurement tools for OpenAPI definitions.

3

4

## Capabilities

5

6

### Analyze OpenAPI Definition

7

8

Comprehensive analysis of OpenAPI definitions to detect features, complexity, and usage patterns.

9

10

```typescript { .api }

11

/**

12

* Analyze an OpenAPI definition for features and complexity

13

* @param definition - OpenAPI definition to analyze

14

* @returns Promise resolving to detailed analysis results

15

*/

16

function analyzer(definition: OASDocument): Promise<OASAnalysis>;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import analyzer from "oas/analyzer";

23

24

const definition = {

25

openapi: "3.1.0",

26

info: { title: "My API", version: "1.0.0" },

27

paths: { /* ... */ }

28

};

29

30

const analysis = await analyzer(definition);

31

32

// General metrics

33

console.log(`Operations: ${analysis.general.operationTotal.found}`);

34

console.log(`File size: ${analysis.general.rawFileSize.found} bytes`);

35

console.log(`Media types: ${analysis.general.mediaTypes.found.join(', ')}`);

36

console.log(`Security types: ${analysis.general.securityTypes.found.join(', ')}`);

37

38

// OpenAPI feature usage

39

console.log(`Uses callbacks: ${analysis.openapi.callbacks.present}`);

40

console.log(`Uses webhooks: ${analysis.openapi.webhooks.present}`);

41

console.log(`Has circular refs: ${analysis.openapi.circularRefs.present}`);

42

43

// ReadMe extension usage

44

console.log(`Custom code samples: ${analysis.readme['x-readme.code-samples'].present}`);

45

console.log(`Static headers: ${analysis.readme['x-readme.headers'].present}`);

46

```

47

48

### Analysis Result Structure

49

50

```typescript { .api }

51

interface OASAnalysis {

52

/** General API metrics and statistics */

53

general: {

54

dereferencedFileSize: OASAnalysisGeneral;

55

mediaTypes: OASAnalysisGeneral;

56

operationTotal: OASAnalysisGeneral;

57

rawFileSize: OASAnalysisGeneral;

58

securityTypes: OASAnalysisGeneral;

59

};

60

/** OpenAPI specification feature usage */

61

openapi: {

62

additionalProperties: OASAnalysisFeature;

63

callbacks: OASAnalysisFeature;

64

circularRefs: OASAnalysisFeature;

65

commonParameters: OASAnalysisFeature;

66

discriminators: OASAnalysisFeature;

67

links: OASAnalysisFeature;

68

style: OASAnalysisFeature;

69

polymorphism: OASAnalysisFeature;

70

serverVariables: OASAnalysisFeature;

71

webhooks: OASAnalysisFeature;

72

xml: OASAnalysisFeature;

73

xmlSchemas: OASAnalysisFeature;

74

xmlRequests: OASAnalysisFeature;

75

xmlResponses: OASAnalysisFeature;

76

};

77

/** ReadMe-specific extension usage */

78

readme: {

79

'x-default': OASAnalysisFeature;

80

'x-readme.code-samples': OASAnalysisFeature;

81

'x-readme.headers': OASAnalysisFeature;

82

'x-readme.explorer-enabled': OASAnalysisFeature;

83

'x-readme.proxy-enabled': OASAnalysisFeature;

84

'x-readme.samples-languages': OASAnalysisFeature;

85

'x-readme-ref-name': OASAnalysisFeature;

86

'x-readme.samples-enabled'?: OASAnalysisFeature;

87

raw_body?: OASAnalysisFeature;

88

};

89

}

90

91

interface OASAnalysisFeature {

92

/** Whether the feature is present in the definition */

93

present: boolean;

94

/** JSON pointer locations where the feature is used */

95

locations: string[];

96

}

97

98

interface OASAnalysisGeneral {

99

/** Feature name for reporting */

100

name: string;

101

/** Found values (strings for enums, numbers for counts) */

102

found: string[] | number;

103

}

104

```

105

106

## Feature Analysis Details

107

108

### General Metrics Analysis

109

110

```typescript

111

const analysis = await analyzer(definition);

112

113

// File size analysis

114

const rawSize = analysis.general.rawFileSize.found as number;

115

const dereferencedSize = analysis.general.dereferencedFileSize.found as number;

116

const expansion = dereferencedSize - rawSize;

117

118

console.log(`Raw file size: ${rawSize} bytes`);

119

console.log(`Dereferenced size: ${dereferencedSize} bytes`);

120

console.log(`Size expansion: ${expansion} bytes (${(expansion/rawSize*100).toFixed(1)}%)`);

121

122

// Operation complexity

123

const opCount = analysis.general.operationTotal.found as number;

124

console.log(`Total operations: ${opCount}`);

125

126

if (opCount > 50) {

127

console.log("Large API - consider using tags for organization");

128

} else if (opCount > 100) {

129

console.log("Very large API - recommend splitting or using reduction");

130

}

131

132

// Media type diversity

133

const mediaTypes = analysis.general.mediaTypes.found as string[];

134

console.log(`Supported media types: ${mediaTypes.length}`);

135

136

if (mediaTypes.includes('application/xml')) {

137

console.log("XML support detected");

138

}

139

if (mediaTypes.some(type => type.includes('multipart'))) {

140

console.log("File upload support detected");

141

}

142

```

143

144

### OpenAPI Feature Detection

145

146

```typescript

147

// Advanced feature usage

148

if (analysis.openapi.callbacks.present) {

149

console.log("API uses callbacks:");

150

analysis.openapi.callbacks.locations.forEach(location => {

151

console.log(` Found at: ${location}`);

152

});

153

}

154

155

if (analysis.openapi.webhooks.present) {

156

console.log("API defines webhooks (OpenAPI 3.1):");

157

analysis.openapi.webhooks.locations.forEach(location => {

158

console.log(` Webhook at: ${location}`);

159

});

160

}

161

162

if (analysis.openapi.circularRefs.present) {

163

console.log("⚠️ Circular references detected:");

164

analysis.openapi.circularRefs.locations.forEach(location => {

165

console.log(` Circular ref: ${location}`);

166

});

167

}

168

169

// Polymorphism usage

170

if (analysis.openapi.polymorphism.present) {

171

console.log("Polymorphic schemas detected:");

172

analysis.openapi.polymorphism.locations.forEach(location => {

173

console.log(` Polymorphism at: ${location}`);

174

});

175

}

176

177

// Parameter serialization complexity

178

if (analysis.openapi.style.present) {

179

console.log("Custom parameter serialization styles:");

180

analysis.openapi.style.locations.forEach(location => {

181

console.log(` Custom style at: ${location}`);

182

});

183

}

184

```

185

186

### ReadMe Extension Analysis

187

188

```typescript

189

// Documentation enhancements

190

if (analysis.readme['x-readme.code-samples'].present) {

191

console.log("Custom code samples defined:");

192

analysis.readme['x-readme.code-samples'].locations.forEach(location => {

193

console.log(` Code sample at: ${location}`);

194

});

195

}

196

197

if (analysis.readme['x-readme.headers'].present) {

198

console.log("Static headers configured:");

199

analysis.readme['x-readme.headers'].locations.forEach(location => {

200

console.log(` Static headers at: ${location}`);

201

});

202

}

203

204

// API Explorer configuration

205

if (analysis.readme['x-readme.explorer-enabled'].present) {

206

console.log("API Explorer settings found");

207

}

208

209

if (analysis.readme['x-readme.proxy-enabled'].present) {

210

console.log("CORS proxy configuration found");

211

}

212

213

// Language preferences

214

if (analysis.readme['x-readme.samples-languages'].present) {

215

console.log("Custom code sample languages configured");

216

}

217

```

218

219

## Advanced Analysis Patterns

220

221

### Complexity Scoring

222

223

```typescript

224

function calculateComplexityScore(analysis: OASAnalysis): number {

225

let score = 0;

226

227

// Base complexity from operation count

228

const opCount = analysis.general.operationTotal.found as number;

229

score += opCount;

230

231

// Feature complexity multipliers

232

if (analysis.openapi.callbacks.present) score += 10;

233

if (analysis.openapi.webhooks.present) score += 8;

234

if (analysis.openapi.circularRefs.present) score += 15;

235

if (analysis.openapi.polymorphism.present) score += 12;

236

if (analysis.openapi.discriminators.present) score += 8;

237

if (analysis.openapi.links.present) score += 6;

238

239

// Media type diversity

240

const mediaTypes = analysis.general.mediaTypes.found as string[];

241

score += mediaTypes.length * 2;

242

243

// Security complexity

244

const securityTypes = analysis.general.securityTypes.found as string[];

245

score += securityTypes.length * 3;

246

247

return score;

248

}

249

250

const complexity = calculateComplexityScore(analysis);

251

console.log(`API complexity score: ${complexity}`);

252

253

if (complexity > 100) {

254

console.log("High complexity API - recommend comprehensive testing");

255

} else if (complexity > 200) {

256

console.log("Very high complexity - consider refactoring or splitting");

257

}

258

```

259

260

### Feature Recommendations

261

262

```typescript

263

function generateRecommendations(analysis: OASAnalysis): string[] {

264

const recommendations: string[] = [];

265

266

// File size recommendations

267

const rawSize = analysis.general.rawFileSize.found as number;

268

if (rawSize > 1000000) { // > 1MB

269

recommendations.push("Consider splitting large API definition into multiple files");

270

}

271

272

// Missing features that could improve API

273

if (!analysis.openapi.commonParameters.present) {

274

recommendations.push("Consider using common parameters to reduce duplication");

275

}

276

277

if (!analysis.readme['x-readme.code-samples'].present) {

278

recommendations.push("Add custom code samples for better developer experience");

279

}

280

281

// Complexity warnings

282

if (analysis.openapi.circularRefs.present) {

283

recommendations.push("Review circular references - they may indicate design issues");

284

}

285

286

// XML-specific recommendations

287

if (analysis.openapi.xml.present && !analysis.openapi.xmlSchemas.present) {

288

recommendations.push("XML usage detected but no XML schemas defined");

289

}

290

291

return recommendations;

292

}

293

294

const recommendations = generateRecommendations(analysis);

295

console.log("\nRecommendations:");

296

recommendations.forEach(rec => console.log(`• ${rec}`));

297

```

298

299

### Comparison Analysis

300

301

```typescript

302

// Compare two API versions

303

async function compareAPIs(oldDef: OASDocument, newDef: OASDocument) {

304

const [oldAnalysis, newAnalysis] = await Promise.all([

305

analyzer(oldDef),

306

analyzer(newDef)

307

]);

308

309

// Operation count changes

310

const oldOps = oldAnalysis.general.operationTotal.found as number;

311

const newOps = newAnalysis.general.operationTotal.found as number;

312

const opChange = newOps - oldOps;

313

314

console.log(`Operations: ${oldOps} → ${newOps} (${opChange >= 0 ? '+' : ''}${opChange})`);

315

316

// New features added

317

const features = [

318

'callbacks', 'webhooks', 'discriminators', 'polymorphism', 'links'

319

] as const;

320

321

features.forEach(feature => {

322

const oldHas = oldAnalysis.openapi[feature].present;

323

const newHas = newAnalysis.openapi[feature].present;

324

325

if (!oldHas && newHas) {

326

console.log(`✨ Added ${feature} support`);

327

} else if (oldHas && !newHas) {

328

console.log(`❌ Removed ${feature} support`);

329

}

330

});

331

332

// File size impact

333

const oldSize = oldAnalysis.general.rawFileSize.found as number;

334

const newSize = newAnalysis.general.rawFileSize.found as number;

335

const sizeChange = ((newSize - oldSize) / oldSize * 100).toFixed(1);

336

337

console.log(`File size change: ${sizeChange}%`);

338

}

339

```

340

341

## Integration Examples

342

343

### API Documentation Pipeline

344

345

```typescript

346

// Generate documentation metadata from analysis

347

async function generateDocMetadata(definition: OASDocument) {

348

const analysis = await analyzer(definition);

349

350

return {

351

complexity: calculateComplexityScore(analysis),

352

features: {

353

hasCallbacks: analysis.openapi.callbacks.present,

354

hasWebhooks: analysis.openapi.webhooks.present,

355

hasCircularRefs: analysis.openapi.circularRefs.present,

356

supportsXML: analysis.openapi.xml.present,

357

customCodeSamples: analysis.readme['x-readme.code-samples'].present

358

},

359

metrics: {

360

operationCount: analysis.general.operationTotal.found,

361

mediaTypes: analysis.general.mediaTypes.found,

362

securityTypes: analysis.general.securityTypes.found

363

},

364

recommendations: generateRecommendations(analysis)

365

};

366

}

367

```

368

369

### Quality Gate Integration

370

371

```typescript

372

// Use analysis for CI/CD quality gates

373

async function validateAPIQuality(definition: OASDocument): Promise<boolean> {

374

const analysis = await analyzer(definition);

375

376

// Quality criteria

377

const hasCircularRefs = analysis.openapi.circularRefs.present;

378

const complexity = calculateComplexityScore(analysis);

379

const opCount = analysis.general.operationTotal.found as number;

380

381

// Fail if quality issues detected

382

if (hasCircularRefs) {

383

console.error("❌ Quality gate failed: Circular references detected");

384

return false;

385

}

386

387

if (complexity > 300) {

388

console.error(`❌ Quality gate failed: Complexity too high (${complexity})`);

389

return false;

390

}

391

392

if (opCount > 150) {

393

console.error(`❌ Quality gate failed: Too many operations (${opCount})`);

394

return false;

395

}

396

397

console.log("✅ API quality gate passed");

398

return true;

399

}

400

```