# Nodes.ts

`

1<comment>/**</comment>

2<comment> * ### Nodes</comment>

3<comment> * Definition of DocsNode classes.</comment>

4<comment> */</comment>

5

6<comment>/** */</comment>

7import { Vnode} from <quote>'hslayout'</quote>;

8import { Log } from <quote>'hsutil'</quote>; const log = new Log(<quote>'Nodes'</quote>);

9import { json } from <quote>'./DocSets'</quote>;

10import { DocSets } from <quote>'./DocSets'</quote>;

11import { DocsType } from <quote>'./Types'</quote>;

12import { DocsNamedType } from <quote>'./Types'</quote>;

13import { DocsReferenceIdType } from <quote>'./Types'</quote>;

14import { Flags } from <quote>'./Flags'</quote>;

15import { flagsNone } from <quote>'./Flags'</quote>;

16import { flagsExported } from <quote>'./Flags'</quote>;

17import { flagsConstLet } from <quote>'./Flags'</quote>;

18import { flagsClass } from <quote>'./Flags'</quote>;

19import { flagsPublic } from <quote>'./Flags'</quote>;

20import { title } from <quote>'./NodesDisplay'</quote>;

21import { DocsComment } from <quote>'./NodesDisplay'</quote>;

22import { commentLong } from <quote>'./NodesDisplay'</quote>;

23import { members } from <quote>'./NodesDisplay'</quote>;

24

25

26<comment>/** fields to exclude from the test */</comment>

27const ignoreFields = [<quote>'FLAGS'</quote>, <quote>'TYPE'</quote>, <quote>'modules'</quote>, <quote>'kindPrint'</quote>];

28

29

30export class DocsNode {

31 static errCount = 0;

32

33 private static makeNode(mdl:json):DocsNode {

34 const node = groupKindTitle[mdl.kind];

35 if (!node) { log.warn(`unknown kind ${mdl.kindString} (${mdl.kind}) for ${mdl.fullPath}`); }

36 else { return new node(mdl); }

37 }

38

39 static traverse(mdl:json, lib:string, path=<quote>''</quote>):DocsNode {

40 mdl.lib = lib;

41 mdl.name = mdl.name.replace(/[<quote>"<quote>'](.+)["</quote>'</quote>]|(.+)/g, <quote>"$1$2"</quote>) <comment>// remove quotes </comment>

42<comment></comment> .replace(/\<comment>//g, <quote>'.'</quote>); // <quote>"a/b"</quote> => <quote>"a.b"</quote> /</comment>

43<comment></comment> mdl.fullPath = (path===<quote>''</quote>)? mdl.name : `${path}.${mdl.name}`;

44 if (DocsNode.errCount>20) { return; }

45 return DocsNode.makeNode(mdl);

46 }

47

48

49 <comment>// All DocsNode fields:</comment>

50<comment></comment> <comment>// - undefined: not allowed</comment>

51<comment></comment> <comment>// - null: optional</comment>

52<comment></comment> <comment>// - els: required</comment>

53<comment></comment> public children:DocsNode[];

54 public comment:DocsComment = null;

55 public defaultValue:string;

56 public extendedBy: DocsReferenceIdType[];

57 public extendedTypes: DocsReferenceIdType[];

58 public FLAGS = flagsNone;

59 public flags: Flags = {};

60 public fullPath:string = null;

61 public getSignature: DocsGetSignature[];

62 public groups:DocsGroup[];

63 public id:number = 0; <comment>// defined = required; null = optional</comment>

64<comment></comment> public indexSignature: DocsIndexSignature[];

65 public implementedTypes: DocsNamedType[];

66 public implementationOf: DocsReferenceIdType;

67 public implementedBy: DocsReferenceIdType[];

68 public inheritedFrom: DocsReferenceIdType;

69 public kind:number = 0;

70 public kindString: string = <quote>''</quote>;

71 public kindPrint: string;

72 public lib:string = null;

73 public name:string = <quote>''</quote>;

74 public originalName:string;

75 public overwrites: DocsReferenceIdType;

76 public parameters:DocsParameter[];

77 public setSignature: DocsSetSignature[];

78 protected signatures: DocsSignature[];

79 public sources: DocsSource[] = [];

80 public target:number;

81 public TYPE = <string[]>[];

82 public type: DocsType = null;

83 public typeParameter:DocsTypeParameter[];

84

85 constructor(mdl:json) {

86 this.id = mdl.id;

87 this.kindString = mdl.kindString || <quote>'root'</quote>;

88 DocSets.addNode(mdl, this);

89 }

90

91 public getName() { return this.name; }

92 public getSignatures() { return this.signatures; }

93 public setSignatures(signatures: DocsSignature[]) { this.signatures = signatures; }

94 public getParameters(params:(s:DocsParamaterized)=>Vnode[]):Vnode {

95 return this.getParameters? params(this) : undefined;

96 }

97

98 public title():Vnode { return title(this); }

99 public commentLong():Vnode { return commentLong(this); }

100 public members():Vnode { return members(this); }

101}

102

103

104const isNotIgnored = (field:string) => ignoreFields.indexOf(field)<0;

105const isExpected = (value:any) => value===null? false : true;

106

107

108<comment>//------------- interfaces -------------------------------------------</comment>

109<comment></comment>export interface DocsGroup {

110 title:string;

111 kind: number;

112 children: number[];

113}

114

115

116export interface DocsSource {

117 fileName: string;

118 line: number;

119 character: number;

120}

121

122export interface DocsParamaterized extends DocsNode {}

123export interface DocsSignature extends DocsParamaterized {}

124

125<comment>//------------- Node class definitions -------------------------------------------</comment>

126<comment></comment>

127<comment>/**</comment>

128<comment> * establishes a mechanism to check for expected or optional properties, as well as </comment>

129<comment> * a set of flags and types, for derived classes.</comment>

130<comment> */</comment>

131export class DocsBaseNode extends DocsNode {

132 mdl:json;

133 constructor(mdl:json) {

134 super(mdl);

135 this.init();

136 this.set(mdl);

137 this.setFlags(mdl.flags);

138 }

139

140 init() {

141 this.FLAGS = flagsNone;

142 }

143

144 set(mdl:json, fields = Object.getOwnPropertyNames(this)) {

145 fields.filter(f=>this[f]!==undefined).forEach(f => { <comment>// expected fields</comment>

146<comment></comment> if (mdl[f]!==undefined) {

147 switch(f) {

148 case <quote>'type'</quote>:

149 if (this.TYPE && this.TYPE.indexOf(mdl[f].type)>=0) {

150 this[f] = DocsType.makeType(mdl[f], this);

151 } else {

152 log.warn(`${this.lib} #${mdl.id}: unexpected type <quote>'${mdl[f].type}'</quote> missing in class <quote>'${this.kindString}'</quote>`);

153 DocsNode.errCount++;

154 }

155 break;

156 case <quote>'comment'</quote>:

157 this[f] = new DocsComment(mdl[f], this); break;

158 case <quote>'children'</quote>:

159 this[f] = mdl.children.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

160 case <quote>'signatures'</quote>:

161 this[f] = mdl.signatures.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

162 case <quote>'indexSignature'</quote>:

163 this[f] = mdl.indexSignature.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

164 case <quote>'setSignature'</quote>:

165 this[f] = mdl.setSignature.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

166 case <quote>'getSignature'</quote>:

167 this[f] = mdl.getSignature.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

168 case <quote>'parameters'</quote>:

169 this[f] = mdl.parameters.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

170 case <quote>'typeParameter'</quote>:

171 this[f] = mdl.typeParameter.map((c:json) => DocsNode.traverse(c, this.lib, mdl.fullPath)); break;

172 default: this[f] = mdl[f];

173 }

174 } else if (isExpected(this[f]) && isNotIgnored(f)) {

175 log.warn(`${this.lib}: <quote>'${this.kindString}'</quote> #${mdl.id}: field <quote>'${f}'</quote> should be optional`);

176 DocsNode.errCount++;

177 }

178 });

179 fields = Object.getOwnPropertyNames(mdl);

180 fields.forEach(f => { <comment>// unexpected fields</comment>

181<comment></comment> if (this[f]===undefined && isNotIgnored(f)) {

182 log.warn(`${this.lib}: <quote>'${this.kindString}'</quote> #${this.id}: found extra field <quote>'${f}'</quote>=<quote>'${log.inspect(mdl[f],2, '</quote> <quote>', null)}'</quote>`);

183 DocsNode.errCount++;

184 }

185 });

186 }

187

188 setFlags(mdlFlags:json) {

189 const staticFlags:Flags = this.FLAGS;

190 Object.keys(staticFlags).forEach(f => { <comment>// expected flags</comment>

191<comment></comment> if (mdlFlags[f]!==undefined) { this.flags[f] = mdlFlags[f]; }

192 else if (staticFlags[f]===true) {

193 log.warn(`<quote>'${this.kindString}'</quote> #${this.id}: flag <quote>'${f}'</quote> should be optional`);

194 DocsNode.errCount++;

195 }

196 });

197 const flags = Object.getOwnPropertyNames(mdlFlags);

198 flags.forEach(f => { <comment>// unexpected flags</comment>

199<comment></comment> if (staticFlags[f]===undefined) {

200 log.warn(`<quote>'${this.kindString}'</quote> #${this.id}: found extra flag <quote>'${f}'</quote>=<quote>'${log.inspect(mdlFlags[f],1)}'</quote>`);

201 DocsNode.errCount++;

202 }

203 });

204 }

205}

206

207class DocsSourced extends DocsBaseNode {

208 init() {

209 super.init();

210 this.sources = [];

211 }

212}

213

214class DocsStructured extends DocsSourced {

215 init() {

216 super.init();

217 this.children = null; <comment>// optional</comment>

218<comment></comment> this.groups = null; <comment>// optional</comment>

219<comment></comment> this.kindString = null; <comment>// optional</comment>

220<comment></comment> this.sources = []; <comment>// required</comment>

221<comment></comment> }

222}

223

224class DocsWithDefault extends DocsSourced {

225 init() {

226 super.init();

227 this.defaultValue = null;

228 }

229}

230

231

232class DocsRoot extends DocsBaseNode {

233 init() {

234 super.init();

235 this.children = null; <comment>// optional</comment>

236<comment></comment> this.groups = []; <comment>// required</comment>

237<comment></comment> this.kindString = null; <comment>// optional for root</comment>

238<comment></comment> this.sources = null; <comment>// optional for root</comment>

239<comment></comment> }

240}

241

242<comment>//-------------- Actual Modules</comment>

243<comment></comment>class DocsExternalModule extends DocsStructured {

244 init() {

245 super.init();

246 this.FLAGS = flagsExported({});

247 this.originalName = <quote>''</quote>;

248 this.kindPrint = <quote>'module'</quote>;

249 }

250}

251

252class DocsModule extends DocsStructured {

253 init() {

254 super.init();

255 this.FLAGS = flagsExported({});

256 this.kindPrint = <quote>'namespace'</quote>;

257 }

258}

259

260class DocsEnumeration extends DocsStructured {

261 init() {

262 super.init();

263 this.FLAGS = flagsExported({});

264 this.kindPrint = <quote>'enumeration'</quote>;

265 }

266}

267

268class DocsUnknown extends DocsBaseNode {

269 init() {

270 this.kindPrint = <quote>'unknown'</quote>;

271 }

272}

273

274class DocsEnumerationMember extends DocsWithDefault {

275 init() {

276 super.init();

277 this.FLAGS = flagsExported({});

278 this.kindPrint = <quote>'enumeration member'</quote>;

279 this.defaultValue = null;

280 }

281}

282

283class DocsVariable extends DocsWithDefault {

284 init() {

285 super.init();

286 this.FLAGS = flagsConstLet({ isOptional:false });

287 this.TYPE = [<quote>'array'</quote>, <quote>'reflection'</quote>, <quote>'intrinsic'</quote>, <quote>'reference'</quote>, <quote>'stringLiteral'</quote>, <quote>'unknown'</quote>, <quote>'union'</quote>, <quote>'tuple'</quote>];

288 this.kindPrint = <quote>''</quote>;

289 }

290}

291

292class DocsFunction extends DocsSourced implements DocsParamaterized {

293 init() {

294 super.init();

295 this.FLAGS = flagsConstLet({});

296 this.signatures = [];

297 this.parameters = null;

298 this.kindPrint = <quote>'function'</quote>;

299 }

300}

301

302class DocsClass extends DocsStructured {

303 init() {

304 super.init();

305 this.FLAGS = flagsClass({});

306 this.extendedTypes = null;

307 this.extendedBy = null;

308 this.implementedTypes = null;

309 this.kindPrint = <quote>'class'</quote>;

310 }

311}

312

313class DocsInterface extends DocsStructured {

314 init() {

315 super.init();

316 this.FLAGS = flagsExported({});

317 this.extendedTypes = null;

318 this.extendedBy = null;

319 this.implementedTypes = null;

320 this.indexSignature = null;

321 this.signatures = null;

322 this.implementedBy = null;

323 this.kindPrint = <quote>'interface'</quote>;

324 }

325

326}

327

328class DocsConstructor extends DocsSourced implements DocsParamaterized {

329 init() {

330 super.init();

331 this.FLAGS = flagsExported({});

332 this.signatures = null;

333 this.overwrites = null;

334 this.inheritedFrom = null;

335 this.parameters = null;

336 this.implementationOf = null;

337 this.kindPrint = <quote>''</quote>;

338 }

339}

340

341class DocsProperty extends DocsWithDefault {

342 init() {

343 super.init();

344 this.TYPE = [<quote>'intrinsic'</quote>, <quote>'array'</quote>, <quote>'reflection'</quote>, <quote>'stringLiteral'</quote>, <quote>'reference'</quote>, <quote>'tuple'</quote>, <quote>'union'</quote>];

345 this.FLAGS = flagsPublic(flagsExported({

346 isStatic: false,

347 isOptional: false,

348 isConstructorProperty: false

349 }));

350 this.overwrites = null;

351 this.inheritedFrom = null;

352 this.implementationOf = null;

353 this.kindPrint = <quote>''</quote>;

354 }

355}

356

357class DocsMethod extends DocsSourced implements DocsParamaterized {

358 init() {

359 super.init();

360 this.FLAGS = flagsPublic(flagsExported({

361 isStatic: false,

362 isAbstract: false,

363 isOptional: false

364 }));

365 this.signatures = [];

366 this.overwrites = null;

367 this.inheritedFrom = null;

368 this.implementationOf = null;

369 this.parameters = null;

370 this.kindPrint = <quote>''</quote>;

371 }

372}

373

374class DocsCallSignature extends DocsBaseNode implements DocsParamaterized {

375 init() {

376 super.init();

377 this.TYPE = [<quote>'reference'</quote>, <quote>'union'</quote>, <quote>'intrinsic'</quote>, <quote>'array'</quote>, <quote>'reflection'</quote>, <quote>'tuple'</quote>];

378 this.FLAGS = flagsPublic(flagsExported({}));

379 this.sources = null;

380 this.parameters = null;

381 this.inheritedFrom = null;

382 this.implementationOf = null;

383 this.overwrites = null;

384 this.typeParameter = null;

385 this.kindPrint = <quote>''</quote>;

386 }

387 public getName() { return this.name === <quote>'__call'</quote>? <quote>''</quote> : this.name; }

388}

389

390export class DocsIndexSignature extends DocsBaseNode {

391 init() {

392 super.init();

393 this.TYPE = [<quote>'array'</quote>, <quote>'reference'</quote>, <quote>'union'</quote>, <quote>'intrinsic'</quote>, <quote>'reflection'</quote>];

394 this.FLAGS = { isExported:false };

395 this.sources = null;

396 this.parameters = [];

397 this.kindPrint = <quote>'index signature'</quote>;

398 }

399}

400

401class DocsConstructorSignature extends DocsBaseNode implements DocsParamaterized {

402 init() {

403 super.init();

404 this.TYPE = [<quote>'reference'</quote>];

405 this.FLAGS = { isExported:false };

406 this.sources = null;

407 this.parameters = null;

408 this.overwrites = null;

409 this.inheritedFrom = null;

410 this.kindPrint = <quote>''</quote>;

411 <comment>// this.kindPrint = <quote>'constructor signature'</quote>;</comment>

412<comment></comment> }

413}

414

415export class DocsParameter extends DocsBaseNode {

416 init() {

417 super.init();

418 this.FLAGS = { isOptional:false, isRest:false, isExported:false };

419 this.TYPE = [<quote>'reference'</quote>, <quote>'intrinsic'</quote>, <quote>'union'</quote>, <quote>'array'</quote>, <quote>'reflection'</quote>, <quote>'typeParameter'</quote>, <quote>'query'</quote>];

420 this.sources = null; <comment>// sources optional</comment>

421<comment></comment> this.defaultValue = null;

422 this.kindPrint = <quote>'parameter'</quote>;

423 }

424}

425

426class DocsTypeLiteral extends DocsStructured {

427 init() {

428 super.init();

429 this.FLAGS = { isExported:false };

430 this.signatures = null;

431 this.indexSignature = null;

432 this.sources = null; <comment>// sources optional</comment>

433<comment></comment> this.kindPrint = <quote>'type literal'</quote>;

434 }

435}

436

437class DocsTypeParameter extends DocsBaseNode {

438 init() {

439 super.init();

440 this.TYPE = [<quote>'typeOperator'</quote>, <quote>'reference'</quote>];

441 this.FLAGS = { isExported:false };

442 this.sources = null;

443 this.kindPrint = <quote>'types parameter'</quote>;

444 }

445}

446

447class DocsAccessors extends DocsSourced implements DocsParamaterized {

448 init() {

449 super.init();

450 this.FLAGS = flagsPublic(flagsExported({

451 isStatic: false

452 }));

453 this.getSignature = null;

454 this.setSignature = null;

455 this.overwrites = null;

456 this.inheritedFrom = null;

457 this.implementationOf = null;

458 this.parameters = null;

459 this.kindPrint = <quote>'accessor'</quote>;

460 }

461 public getSignatures() { return this.getSignature || this.setSignature || this.signatures; }

462 <comment>// public getParameters(params:(s:DocsParamaterized)=>Vnode[]):Vnode { </comment>

463<comment></comment> <comment>// // const sigs = this.getSignatures();</comment>

464<comment></comment> <comment>// // return !sigs? [] : sigs.map((sig:any) => m(<quote>'span'</quote>, <quote>'/Accessor type/'</quote> <comment>/* sig.type() */</comment>)); </comment>

465<comment></comment> <comment>// return this.parameters? params(this) : []; </comment>

466<comment></comment> <comment>// }</comment>

467<comment></comment>}

468

469export class DocsGetSignature extends DocsBaseNode {

470 init() {

471 this.TYPE = [<quote>'intrinsic'</quote>, <quote>'reference'</quote>, <quote>'union'</quote>, <quote>'array'</quote>, <quote>'reflection'</quote>, <quote>'stringLiteral'</quote>];

472 this.FLAGS = { isExported:false };

473 this.kindPrint = <quote>'get'</quote>;

474 this.sources = undefined;

475 this.overwrites = null;

476 this.inheritedFrom = null;

477 }

478}

479

480export class DocsSetSignature extends DocsBaseNode {

481 init() {

482 this.kindPrint = <quote>'set'</quote>;

483 this.sources = undefined;

484 this.parameters = [];

485 this.TYPE = [<quote>'intrinsic'</quote>, <quote>'stringLiteral'</quote>];

486 this.FLAGS = { isExported:false };

487 }

488}

489

490class DocsObjectLiteral extends DocsStructured implements DocsParamaterized {

491 init() {

492 super.init();

493 this.TYPE = [<quote>'intrinsic'</quote>];

494 this.FLAGS = flagsPublic(flagsExported({

495 isStatic: false,

496 isConst: false

497 }));

498 this.parameters = null;

499 this.inheritedFrom = null;

500 }

501}

502

503class DocsTypeAlias extends DocsSourced {

504 init() {

505 super.init();

506 this.FLAGS = flagsExported({});

507 this.TYPE = [<quote>'intrinsic'</quote>, <quote>'union'</quote>, <quote>'array'</quote>, <quote>'tuple'</quote>, <quote>'reflection'</quote>, <quote>'reference'</quote>];

508 this.kindPrint = <quote>'type'</quote>;

509 }

510}

511

512class DocsReference extends DocsBaseNode {

513 init() {

514 super.init();

515 this.FLAGS = { isExported:false };

516 this.TYPE = [];

517 this.kindPrint = <quote>'reference'</quote>;

518 <comment>// optionals:</comment>

519<comment></comment> this.sources = undefined;

520 <comment>// required:</comment>

521<comment></comment> this.target = 0;

522 }

523}

524

525export const groupKindTitle = {

526 0: DocsRoot,

527 1: DocsExternalModule,

528 2: DocsModule,

529 4: DocsEnumeration,

530 8: DocsUnknown,

531 16: DocsEnumerationMember,

532 32: DocsVariable,

533 64: DocsFunction,

534 128: DocsClass,

535 256: DocsInterface,

536 512: DocsConstructor,

537 1024: DocsProperty,

538 2048: DocsMethod,

539 4096: DocsCallSignature,

540 8192: DocsIndexSignature,

541 16384: DocsConstructorSignature,

542 32768: DocsParameter,

543 65536: DocsTypeLiteral,

544 131072: DocsTypeParameter,

545 262144: DocsAccessors,

546 524288: DocsGetSignature,

547 1048576: DocsSetSignature,

548 2097152: DocsObjectLiteral,

549 4194304: DocsTypeAlias,

550

551 16777216:DocsReference

552};

553

`