Skip to content

Commit

Permalink
Use key-value-pairs instead of positional arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
flobernd committed Jun 25, 2024
1 parent 43080f9 commit f0196fa
Show file tree
Hide file tree
Showing 22 changed files with 140 additions and 131 deletions.
2 changes: 1 addition & 1 deletion compiler/src/model/metamodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export class Container extends VariantBase {
export class Inherits {
type: TypeName
generics?: ValueOf[]
meta?: string[]
meta?: { [p: string]: string }
}

/**
Expand Down
19 changes: 14 additions & 5 deletions compiler/src/model/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import * as model from './metamodel'
import { EOL } from 'os'
import { dirname, join, sep } from 'path'
import { readFileSync } from 'fs'
import {CgroupCpuStat} from "../../../specification/nodes/_types/Stats";

const docIds: string[][] = readFileSync(join(__dirname, '..', '..', '..', 'specification', '_doc_ids', 'table.csv'), 'utf8')
.split('\n')
Expand Down Expand Up @@ -418,17 +419,25 @@ export function modelBehaviors (node: ExpressionWithTypeArguments, jsDocs: JSDoc
const behaviorName = node.getExpression().getText()
const generics = node.getTypeArguments().map(node => modelType(node))

let meta: string[] | undefined
let meta: Map<string, string> | undefined
const tags = parseJsDocTagsAllowDuplicates(jsDocs)
if (tags.behavior_meta !== undefined) {
// Splits a string by comma, but preserves comma in quoted strings
const re = /(?<=")[^"]+?(?="(?:\s*?,|\s*?$))|(?<=(?:^|,)\s*?)(?:[^,"\s][^,"]*[^,"\s])|(?:[^,"\s])(?![^"]*?"(?:\s*?,|\s*?$))(?=\s*?(?:,|$))/g
// Extracts whitespace/comma-separated key-value-pairs with a "=" delimiter and handles double-quotes
const re = /(?<key>[^=\s,]+)=(?<value>"([^"]*)"|([^\s,]+))/g

for (const tag of tags.behavior_meta) {
const id = tag.split(' ')
if (id[0].trim() !== behaviorName) {
continue
}
meta = id.slice(1).join(' ').match(re) as string[]
const matches = [...id.slice(1).join(' ').matchAll(re)];
meta = new Map<string, string>()
for (const match of matches) {
if (match.groups == null) {
continue
}
meta.set(match.groups.key, match.groups.value.replace(/^"(.+(?="$))"$/, '$1'))
}
break
}
}
Expand All @@ -439,7 +448,7 @@ export function modelBehaviors (node: ExpressionWithTypeArguments, jsDocs: JSDoc
namespace: getNameSpace(node)
},
...(generics.length > 0 && { generics }),
meta
meta: (meta === undefined) ? undefined : Object.fromEntries(meta)
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/steps/validate-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,10 +653,10 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma
for (const parent of typeDef.behaviors) {
validateTypeRef(parent.type, parent.generics, openGenerics)

if (parent.type.name === 'AdditionalProperty' && (parent.meta == null || parent.meta.length < 2 || parent.meta.length > 3)) {
if (parent.type.name === 'AdditionalProperty' && (parent.meta == null || parent.meta.name == null || parent.meta.value == null)) {
modelError(`AdditionalProperty behavior for type '${fqn(typeDef.name)}' requires a 'behavior_meta' decorator with at least 2 arguments (name of name, name of value, description)`)
}
if (parent.type.name === 'AdditionalProperties' && (parent.meta == null || parent.meta.length !== 2)) {
if (parent.type.name === 'AdditionalProperties' && (parent.meta == null || parent.meta.name == null || parent.meta.description == null)) {
modelError(`AdditionalProperties behavior for type '${fqn(typeDef.name)}' requires a 'behavior_meta' decorator with exactly 2 arguments (name, description)`)
}
}
Expand Down
4 changes: 2 additions & 2 deletions docs/behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ We therefore document the requirement to behave like a dictionary for unknown pr

```ts
/**
* @behavior_meta AdditionalProperties sub_aggregations
* @behavior_meta AdditionalProperties name=sub_aggregations
*/
class IpRangeBucket implements AdditionalProperties<AggregateName, Aggregate> {}
```
Expand All @@ -25,7 +25,7 @@ There are also many places where we expect only one runtime-defined property, su

```ts
/**
* @behavior_meta AdditionalProperty field, bounding_box
* @behavior_meta AdditionalProperty name=field value=bounding_box
*/
class GeoBoundingBoxQuery extends QueryBase
implements AdditionalProperty<Field, BoundingBox>
Expand Down
Loading

0 comments on commit f0196fa

Please sign in to comment.