-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement OrderedDictionary<K, V>
type
#3913
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,6 +88,7 @@ export class DictionaryOf { | |
key: ValueOf | ||
value: ValueOf | ||
singleKey: boolean | ||
ordered: boolean | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -281,7 +281,8 @@ export function modelType (node: Node): model.ValueOf { | |
kind: 'dictionary_of', | ||
key, | ||
value, | ||
singleKey: false | ||
singleKey: false, | ||
ordered: false | ||
} | ||
return type | ||
} | ||
|
@@ -294,7 +295,21 @@ export function modelType (node: Node): model.ValueOf { | |
kind: 'dictionary_of', | ||
key, | ||
value, | ||
singleKey: true | ||
singleKey: true, | ||
ordered: false | ||
} | ||
return type | ||
} | ||
|
||
case 'OrderedDictionary': { | ||
assert(node, node.getTypeArguments().length === 2, 'A OrderedDictionary must have two arguments') | ||
const [key, value] = node.getTypeArguments().map(node => modelType(node)) | ||
const type: model.DictionaryOf = { | ||
kind: 'dictionary_of', | ||
key, | ||
value, | ||
singleKey: false, | ||
ordered: true | ||
} | ||
return type | ||
} | ||
|
@@ -500,7 +515,7 @@ export function modelEnumDeclaration (declaration: EnumDeclaration): model.Enum | |
} | ||
|
||
if (typeof tags.es_quirk === 'string') { | ||
type.esQuirk = tags.es_quirk | ||
type.esQuirk = tags.es_quirk.replace(/\r/g, '') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Window-ism? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes 😵💫 I had applied this to most other places a while ago, but seems like I forgot about the quirks. This will ensure deterministic output regardless of being generated on *nix or Windows. |
||
} | ||
|
||
return type | ||
|
@@ -892,7 +907,7 @@ function hoistPropertyAnnotations (property: model.Property, jsDocs: JSDoc[]): v | |
assert(jsDocs, value === 'container_property', `Unknown 'variant' value '${value}' on property ${property.name}`) | ||
property.containerProperty = true | ||
} else if (tag === 'es_quirk') { | ||
property.esQuirk = value | ||
property.esQuirk = value.replace(/\r/g, '') | ||
} else { | ||
assert(jsDocs, false, `Unhandled tag: '${tag}' with value: '${value}' on property ${property.name}`) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -396,17 +396,17 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma | |
const inheritedProps = inheritedProperties(typeDef) | ||
|
||
context.push('path') | ||
validateProperties(typeDef.path, openGenerics, inheritedProps) | ||
validateProperties(fqn(typeDef.name), typeDef.path, openGenerics, inheritedProps) | ||
context.pop() | ||
|
||
context.push('query') | ||
validateProperties(typeDef.query, openGenerics, inheritedProps) | ||
validateProperties(fqn(typeDef.name), typeDef.query, openGenerics, inheritedProps) | ||
context.pop() | ||
|
||
context.push('body') | ||
switch (typeDef.body.kind) { | ||
case 'properties': | ||
validateProperties(typeDef.body.properties, openGenerics, inheritedProps) | ||
validateProperties(fqn(typeDef.name), typeDef.body.properties, openGenerics, inheritedProps) | ||
break | ||
case 'value': | ||
validateValueOf(typeDef.body.value, openGenerics) | ||
|
@@ -433,7 +433,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma | |
|
||
switch (typeDef.body.kind) { | ||
case 'properties': | ||
validateProperties(typeDef.body.properties, openGenerics, inheritedProperties(typeDef)) | ||
validateProperties(fqn(typeDef.name), typeDef.body.properties, openGenerics, inheritedProperties(typeDef)) | ||
break | ||
case 'value': | ||
validateValueOf(typeDef.body.value, openGenerics) | ||
|
@@ -507,7 +507,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma | |
|
||
validateInherits(typeDef.inherits, openGenerics) | ||
validateBehaviors(typeDef, openGenerics) | ||
validateProperties(typeDef.properties, openGenerics, inheritedProperties(typeDef)) | ||
validateProperties(fqn(typeDef.name), typeDef.properties, openGenerics, inheritedProperties(typeDef)) | ||
|
||
if (typeDef.variants?.kind === 'container') { | ||
const variants = typeDef.properties.filter(prop => !(prop.containerProperty ?? false)) | ||
|
@@ -747,7 +747,7 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma | |
return false | ||
} | ||
|
||
function validateProperties (props: model.Property[], openGenerics: Set<string>, inheritedProperties: Set<string>): void { | ||
function validateProperties (type: string, props: model.Property[], openGenerics: Set<string>, inheritedProperties: Set<string>): void { | ||
const allIdentifiers = new Set<string>() | ||
const allNames = new Set<string>() | ||
|
||
|
@@ -773,6 +773,13 @@ export default async function validateModel (apiModel: model.Model, restSpec: Ma | |
} | ||
|
||
context.push(`Property '${prop.name}'`) | ||
|
||
if (prop.type.kind === 'dictionary_of' && prop.type.ordered) { | ||
if (prop.name !== 'aggregations') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check only works for the "top-level" type of properties and does not check the type-name, but I think this is sufficient for now. WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this is to catch the many occurrences of It seems a bit brittle, but will ensure we can easily use ... which makes me think that ideally we should have a validation that forbids There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Correct!
I don't think there is a good way to detect this using a pattern. We have also cases like this: Dictionary<string, ApiKeyAggregationContainer> where we define special containers to restrict the valid aggregations to a subset. |
||
modelError(`OrderedDictionary can not be used for property '${prop.name}' on type '${type}'.`) | ||
} | ||
} | ||
|
||
validateValueOf(prop.type, openGenerics) | ||
validateValueOfJsonEvents(prop.type) | ||
context.pop() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side comment: interesting case of a boolean property (
singleKey
) that evolves into an enum (singleKey
,ordered
,unordered
) asordered
only makes sense whensingleKey == false
.We can however keep it as two properties:
ordered
because it makes no difference to them,ordered
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was thinking about an enum, but I as well didn't want to break all existing tooling 😅