Skip to content

Commit

Permalink
Add normalisation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
daogrady committed Jan 9, 2025
1 parent bebe67a commit 3e74d08
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 16 deletions.
6 changes: 3 additions & 3 deletions lib/components/enum.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { normalise } = require('./identifier')
const { enquote } = require('./identifier')

/**
* Extracts all unique values from a list of enum key-value pairs.
Expand Down Expand Up @@ -57,7 +57,7 @@ function printEnum(buffer, name, kvs, options = {}, doc=[]) {
buffer.add('// enum')
if (opts.export) buffer.add(doc)
buffer.addIndentedBlock(`${opts.export ? 'export ' : ''}const ${name} = {`, () =>
kvs.forEach(([k, v]) => { buffer.add(`${normalise(k)}: ${v},`) })
kvs.forEach(([k, v]) => { buffer.add(`${enquote(k)}: ${v},`) })
, '} as const;')
buffer.add(`${opts.export ? 'export ' : ''}type ${name} = ${stringifyEnumType(kvs)}`)
buffer.blankLine()
Expand Down Expand Up @@ -124,7 +124,7 @@ const isInlineEnumType = (element, csn) => element.enum
* @param {[string, string][]} kvs - a list of key-value pairs. Values that are falsey are replaced by
*/
// ??= for inline enums. If there is some static property of that name, we don't want to override it (for example: ".actions"
const stringifyEnumImplementation = (name, kvs) => `module.exports.${name} ??= { ${kvs.map(([k,v]) => `${normalise(k)}: ${v}`).join(', ')} }`
const stringifyEnumImplementation = (name, kvs) => `module.exports.${name} ??= { ${kvs.map(([k,v]) => `${enquote(k)}: ${v}`).join(', ')} }`


module.exports = {
Expand Down
30 changes: 26 additions & 4 deletions lib/components/identifier.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
const isValidIdent = /^[_$a-zA-Z][$\w]*$/

/**
* Normalises an identifier to a valid JavaScript identifier.
* Enquotes an identifier to a valid JavaScript identifier.
* I.e. either the identifier itself or a quoted string.
* This function is suited to escape properties with exotic characters.
* To handle class names, see {@link normalise}.
* @param {string} ident - the identifier to normalise
* @returns {string} the normalised identifier
*/
const normalise = ident => ident && !isValidIdent.test(ident)
const enquote = ident => ident && !isValidIdent.test(ident)
? `"${ident}"`
: ident

Expand All @@ -17,7 +19,27 @@ const normalise = ident => ident && !isValidIdent.test(ident)
*/
const last = ident => ident.split('.').at(-1) ?? ident


/**
* Normalises the name of a service or entity.
* This function is suited to normalise class names.
* To handle properties with exotic characters, see {@link enquote}.
* @param {string} name - name of the entity or fq thereof.
*/
const normalise = name => {
const simple = /** @type {string} */ (name.split('.').at(-1))
const normalised = simple.match(/^[a-zA-Z]+\w*$/)
? simple
: `__${simple.replaceAll(/[^a-zA-Z0-9]/g, '_')}`
return {
simple,
normalised,
isNormalised: simple !== normalised
}
}

module.exports = {
normalise,
last
enquote,
last,
normalise
}
8 changes: 4 additions & 4 deletions lib/components/inline.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { configuration } = require('../config')
const { SourceFile, Buffer } = require('../file')
const { normalise } = require('./identifier')
const { enquote } = require('./identifier')
const { docify } = require('../printers/wrappers')

/** @typedef {import('../resolution/resolver').TypeResolveInfo} TypeResolveInfo */
Expand Down Expand Up @@ -193,7 +193,7 @@ class FlatInlineDeclarationResolver extends InlineDeclarationResolver {
? Object.entries(type.typeInfo.structuredType).map(
([k,v]) => this.flatten({prefix: `${this.prefix(prefix)}${k}`, type: v, modifiers}) // for flat we pass the modifiers!
).flat()
: [`${this.stringifyModifiers(modifiers)}${normalise(prefix)}${this.getPropertyTypeSeparator()} ${this.getPropertyDatatype(type)}`]
: [`${this.stringifyModifiers(modifiers)}${enquote(prefix)}${this.getPropertyTypeSeparator()} ${this.getPropertyDatatype(type)}`]
}

/**
Expand Down Expand Up @@ -254,7 +254,7 @@ class StructuredInlineDeclarationResolver extends InlineDeclarationResolver {
this.printDepth++
const lineEnding = this.printDepth > 1 ? ',' : statementEnd
if (type.typeInfo.structuredType) {
const prefix = fq ? `${this.stringifyModifiers(modifiers)}${normalise(fq)}${this.getPropertyTypeSeparator()}`: ''
const prefix = fq ? `${this.stringifyModifiers(modifiers)}${enquote(fq)}${this.getPropertyTypeSeparator()}`: ''
buffer.add(`${prefix} {`)
buffer.indent()
for (const [n, t] of Object.entries(type.typeInfo.structuredType)) {
Expand All @@ -263,7 +263,7 @@ class StructuredInlineDeclarationResolver extends InlineDeclarationResolver {
buffer.outdent()
buffer.add(`}${this.getPropertyDatatype(type, '')}${lineEnding}`)
} else {
buffer.add(`${this.stringifyModifiers(modifiers)}${normalise(fq)}${this.getPropertyTypeSeparator()} ${this.getPropertyDatatype(type)}${lineEnding}`)
buffer.add(`${this.stringifyModifiers(modifiers)}${enquote(fq)}${this.getPropertyTypeSeparator()} ${this.getPropertyDatatype(type)}${lineEnding}`)
}
this.printDepth--
return buffer
Expand Down
10 changes: 5 additions & 5 deletions lib/file.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const fs = require('fs').promises
const path = require('path')
const { readFileSync } = require('fs')
const { printEnum, propertyToInlineEnumName, stringifyEnumImplementation } = require('./components/enum')
const { normalise } = require('./components/identifier')
const { enquote } = require('./components/identifier')
const { empty } = require('./components/typescript')
const { proxyAccessFunction } = require('./components/javascript')
const { createObjectOf, stringIdent } = require('./printers/wrappers')
Expand Down Expand Up @@ -189,21 +189,21 @@ class SourceFile extends File {
*/
static stringifyLambda({name, parameters=[], returns='any', kind, initialiser, isStatic=false, callStyles={positional:true, named:true}, doc}) {
let docStr = doc?.length ? doc.join('\n')+'\n' : ''
const parameterTypes = parameters.map(({name, modifier, type, doc}) => `${doc?'\n'+doc:''}${normalise(name)}${modifier}: ${type}`).join(', ')
const parameterTypes = parameters.map(({name, modifier, type, doc}) => `${doc?'\n'+doc:''}${enquote(name)}${modifier}: ${type}`).join(', ')
const parameterTypeAsObject = parameterTypes.length
? createObjectOf(parameterTypes)
: empty
const callableSignatures = []
if (callStyles.positional) {
const paramTypesPositional = parameters.map(({name, type, doc}) => `${doc?'\n'+doc:''}${normalise(name)}: ${type}`).join(', ') // must not include ? modifiers
const paramTypesPositional = parameters.map(({name, type, doc}) => `${doc?'\n'+doc:''}${enquote(name)}: ${type}`).join(', ') // must not include ? modifiers
callableSignatures.push('// positional',`${docStr}(${paramTypesPositional}): ${returns}`) // docs shows up on action consumer side: `.action(...)`
}
if (callStyles.named) {
const parameterNames = createObjectOf(parameters.map(({name}) => normalise(name)).join(', '))
const parameterNames = createObjectOf(parameters.map(({name}) => enquote(name)).join(', '))
callableSignatures.push('// named',`${docStr}(${parameterNames}: ${parameterTypeAsObject}): ${returns}`)
}
if (callableSignatures.length === 0) throw new Error('At least one call style must be specified')
let prefix = name ? `${normalise(name)}: `: ''
let prefix = name ? `${enquote(name)}: `: ''
if (prefix && isStatic) {
prefix = `static ${prefix}`
}
Expand Down

0 comments on commit 3e74d08

Please sign in to comment.