diff --git a/compiler/src/model/metamodel.ts b/compiler/src/model/metamodel.ts index f11642c119..7e70a27dc0 100644 --- a/compiler/src/model/metamodel.ts +++ b/compiler/src/model/metamodel.ts @@ -183,7 +183,10 @@ export class ExternalTag { export class InternalTag { kind: 'internal_tag' - tag: string // Name of the property that holds the variant tag + /* Name of the property that holds the variant tag */ + tag: string + /* Default value for the variant tag if it's missing */ + defaultTag?: string } export class Container { diff --git a/compiler/src/model/utils.ts b/compiler/src/model/utils.ts index cc4f6ed949..1fa96255b8 100644 --- a/compiler/src/model/utils.ts +++ b/compiler/src/model/utils.ts @@ -954,7 +954,7 @@ export function parseVariantsTag (jsDoc: JSDoc[]): model.Variants | undefined { return undefined } - const [type, value] = tags.variants.split(' ') + const [type, ...values] = tags.variants.split(' ') if (type === 'external') { return { kind: 'external_tag' } } @@ -964,14 +964,14 @@ export function parseVariantsTag (jsDoc: JSDoc[]): model.Variants | undefined { } assert(jsDoc, type === 'internal', `Bad variant type: ${type}`) - assert(jsDoc, typeof value === 'string', 'Internal variant requires a tag definition') - const [tag, property] = value.split('=') - assert(jsDoc, tag === 'tag', 'The tag name should be "tag"') - assert(jsDoc, typeof property === 'string', 'The tag property is not defined') + + const pairs = parseKeyValues(jsDoc, values, 'tag', 'default') + assert(jsDoc, typeof pairs.tag === 'string', 'Internal variant requires a tag definition') return { kind: 'internal_tag', - tag: property.replace(/'/g, '') + tag: pairs.tag, + defaultTag: pairs.default } } @@ -1000,6 +1000,21 @@ export function parseCommaSeparated (value: string): string[] { return value.split(',').map(v => v.trim().replace(/["']/g, '')) } +/** + * Parses an array of "key=value" pairs and validate key names. Values can optionally be enclosed with single + * or double quotes. + */ +export function parseKeyValues (node: Node | Node[], pairs: string[], ...validKeys: string[]): Record { + const result = {} + pairs.forEach(item => { + const kv = item.split('=') + assert(node, kv.length === 2, 'Malformed key/value list') + assert(node, validKeys.includes(kv[0]), `Unknown key '${kv[0]}'`) + result[kv[0]] = kv[1].replace(/["']/g, '') + }) + return result +} + /** * Given a declaration, returns true if the declaration * if defined but never used, false otherwise. diff --git a/output/schema/schema.json b/output/schema/schema.json index aecd956972..86352810f0 100644 --- a/output/schema/schema.json +++ b/output/schema/schema.json @@ -49972,6 +49972,7 @@ "kind": "union_of" }, "variants": { + "defaultTag": "custom", "kind": "internal_tag", "tag": "type" } @@ -58741,6 +58742,7 @@ "kind": "union_of" }, "variants": { + "defaultTag": "object", "kind": "internal_tag", "tag": "type" } diff --git a/specification/_types/analysis/analyzers.ts b/specification/_types/analysis/analyzers.ts index a12be9199b..75bf8296ab 100644 --- a/specification/_types/analysis/analyzers.ts +++ b/specification/_types/analysis/analyzers.ts @@ -110,7 +110,7 @@ export class WhitespaceAnalyzer { version?: VersionString } -/** @variants internal tag='type' */ +/** @variants internal tag='type' default='custom' */ export type Analyzer = | CustomAnalyzer | FingerprintAnalyzer diff --git a/specification/_types/mapping/Property.ts b/specification/_types/mapping/Property.ts index 332fdf8614..03013599c9 100644 --- a/specification/_types/mapping/Property.ts +++ b/specification/_types/mapping/Property.ts @@ -50,7 +50,7 @@ export class PropertyBase { fields?: Dictionary } -/** @variants internal tag='type' */ +/** @variants internal tag='type' default='object' */ export type Property = | FlattenedProperty | JoinProperty