discrepancy between an internal and external references resolution (`$ref`)
#143 opened on Feb 1, 2018
Repository metrics
- Stars
- (3,302 stars)
- PR merge metrics
- (No merged PRs in 30d)
Description
Hi @bcherny,
Once again, thanks for your great work!
I'm having a strange situation, might be considered as a bug, or a feature... depends on your interpretation. For me it's kinda inconsistent.
I have a scenario.schema.json file where I define an entity, it has internal sub-definitions (used for money, enums, etc.). It looks like the following:
{
"title": "Scenario",
"type": "object",
"properties": {
"id": {
"type": "string",
"faker": "random.uuid"
},
"name": {
"type": "string",
"faker": {
"fake": "{{company.bsNoun}} improvement"
}
},
"description": {
"type": "string",
"faker": "lorem.sentences"
},
"sharing": {
"$ref": "#/definitions/ScenarioSharing"
},
"currentVersion": {
"type": "string",
"pattern": "v0\\.\\d"
},
"lastRun": {
"type": "string",
"faker": "date.past"
},
"versions": {
"type": "array",
"items": {
"$ref": "#/definitions/VersionDefinition"
}
},
"summary": {
"$ref": "#/definitions/ScenarioSummary"
}
},
"additionalProperties": false,
"required": [
"id",
"name",
"description",
"sharing",
"currentVersion",
"lastRun",
"versions",
"summary"
],
"definitions": {
"ScenarioSharing": {
"enum": [
"PUBLIC",
"PRIVATE"
]
},
"Currency": {
"enum": [
"USD",
"EUR",
"CHF",
"GBP"
]
},
"VersionDefinition": {
"type": "object",
"properties": {
"version": {
"type": "string",
"pattern": "v0\\.\\d"
},
"date": {
"type": "string",
"faker": {
"date.between": ["2018-01-01", "2018-12-31"]
}
},
"editor": {
"type": "string",
"faker": "name.findName"
},
"notes": {
"type": "string",
"faker": "lorem.sentence"
}
},
"additionalProperties": false,
"required": [
"version",
"date",
"editor",
"notes"
]
},
"ScenarioSummary": {
"type": "object",
"properties": {
"startDate": {
"type": "string",
"faker": {
"date.between": ["2019-01-01", "2019-12-31"]
}
},
"endDate": {
"type": "string",
"faker": {
"date.between": ["2020-01-01", "2020-12-31"]
}
},
"projectCost": {
"$ref": "#/definitions/Money"
},
"BAUCost": {
"$ref": "#/definitions/Money"
}
},
"additionalProperties": false,
"required": [
"startDate",
"endDate",
"projectCost",
"BAUCost"
]
},
"Money": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"faker": {
"random.number": {
"min": 100000,
"max": 10000000,
"precision": 10000
}
}
},
"currency": {
"$ref": "#/definitions/Currency"
}
},
"additionalProperties": false,
"required": [
"amount",
"currency"
]
}
}
}
I have another file which is just a collection of these entities:
{
"title": "Scenarios",
"type": "array",
"items": {
"$ref": "api/modelling/scenario.schema.json"
}
}
.
I use both files in a RAML contract (generating html docs with raml2html and .d.ts files with your lib here). They need separate schema files, since GET /scenarios is different than GET /scenarios/{id}.
For a single scenario schema I get following:
// Auto-generated with `raml-to-typescript`/`json-schema-to-typescript`
export type ScenarioSharing = "PUBLIC" | "PRIVATE";
export type Currency = "USD" | "EUR" | "CHF" | "GBP";
export interface Scenario {
id: string;
name: string;
description: string;
sharing: ScenarioSharing;
currentVersion: string;
lastRun: string;
versions: VersionDefinition[];
summary: ScenarioSummary;
}
export interface VersionDefinition {
version: string;
date: string;
editor: string;
notes: string;
}
export interface ScenarioSummary {
startDate: string;
endDate: string;
projectCost: Money;
BAUCost: Money;
}
export interface Money {
amount: number;
currency: Currency;
}
whereas for array with external reference, I get:
// Auto-generated with `raml-to-typescript`/`json-schema-to-typescript`
export type Scenarios = Scenario[];
export interface Scenario {
id: string;
name: string;
description: string;
sharing: "PUBLIC" | "PRIVATE";
currentVersion: string;
lastRun: string;
versions: {
version: string;
date: string;
editor: string;
notes: string;
}[];
summary: {
startDate: string;
endDate: string;
projectCost: {
amount: number;
currency: "USD" | "EUR" | "CHF" | "GBP";
};
BAUCost: {
amount: number;
currency: "USD" | "EUR" | "CHF" | "GBP";
};
};
}
Semantically (from TS point of view), the structures are the same. However, internal references get normalized and "compiled into" the external file. I think it would be better if you normalized schemas after all $ref get resolved (no intermediate resolutions along the way).
What is your opinion on this?