From 2116e42720fa6f568e4de90304b993c3dca8d46e Mon Sep 17 00:00:00 2001 From: Daniel O'Grady <103028279+daogrady@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:53:08 +0200 Subject: [PATCH] Visit services and print their name as default export (#86) --- lib/components/resolver.js | 5 ++++- lib/file.js | 18 ++++++++++++++++++ lib/visitor.js | 12 ++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/components/resolver.js b/lib/components/resolver.js index b2f1de20..bfbc1903 100644 --- a/lib/components/resolver.js +++ b/lib/components/resolver.js @@ -312,10 +312,13 @@ class Resolver { * read from left to right which does not contain a kind 'context' or 'service'. * That is, if in the above example 'D' is a context and 'E' is a service, * the resulting namespace is 'a.b.c'. - * @param {string[]} pathParts the distinct parts of the namespace, i.e. ['a','b','c','D','E'] + * @param {string[] | string} pathParts the distinct parts of the namespace, i.e. ['a','b','c','D','E'] or a single path interspersed with periods * @returns {string} the namespace's name, i.e. 'a.b.c'. */ resolveNamespace(pathParts) { + if (typeof pathParts === 'string') { + pathParts = pathParts.split('.') + } let result while (result === undefined) { const path = pathParts.join('.') diff --git a/lib/file.js b/lib/file.js index 5ea4ee23..e9835e93 100644 --- a/lib/file.js +++ b/lib/file.js @@ -122,6 +122,8 @@ class SourceFile extends File { this.typeNames = {} /** @type {[string, string, string][]} */ this.inflections = [] + /** @type {{ buffer: Buffer, names: string[]}} */ + this.services = { buffer: new Buffer(), names: [] } } /** @@ -326,6 +328,19 @@ class SourceFile extends File { this.types.add(`export type ${clean} = ${rhs};`) } + /** + * Adds a service to the file. + * We consider each service its own distinct namespace and therefore expect + * at most one service per file. + * @param {string} fq the fully qualified name of the service + */ + addService(fq) { + if (this.services.names.length) { + throw new Error(`trying to add more than one service to file ${this.path.asDirectory()}. Existing service is ${this.services.names[0]}, trying to add ${fq}`) + } + this.services.names.push(fq) + } + /** * Writes all imports to a buffer, relative to the current file. * Creates a new buffer on each call, as concatenating import strings directly @@ -362,6 +377,7 @@ class SourceFile extends File { this.classes.join(), this.events.buffer.join(), this.actions.buffer.join(), + this.services.buffer.join() // should be at the end ].filter(Boolean).join('\n') } @@ -394,6 +410,8 @@ class SourceFile extends File { .concat(this.enums.fqs.map(({name, fq, property}) => property ? stringifyAnonymousEnum(name, fq, property) : stringifyNamedEnum(name, fq))) + // FIXME: move stringification of service into own module + .concat(this.services.names.map(name => `module.exports.default = { name: '${name}' }`)) // there should be only one .join('\n') + '\n' } } diff --git a/lib/visitor.js b/lib/visitor.js index 00af88f8..57e67129 100644 --- a/lib/visitor.js +++ b/lib/visitor.js @@ -367,6 +367,15 @@ class Visitor { buffer.add('}') } + #printService(name, service) { + this.logger.debug(`Printing service ${name}:\n${JSON.stringify(service, null, 2)}`) + const ns = this.resolver.resolveNamespace(name) + const file = this.getNamespaceFile(ns) + // service.name is clean of namespace + file.services.buffer.add(`export default { name: '${service.name}' }`) + file.addService(service.name) + } + /** * Visits a single entity from the CSN's definition field. * Will call #printEntity or #printAction based on the entity's kind. @@ -393,6 +402,9 @@ class Visitor { case 'event': this.#printEvent(name, entity) break + case 'service': + this.#printService(name, entity) + break default: this.logger.error(`Unhandled entity kind '${entity.kind}'.`) }