Skip to content

Commit 7c14d2a

Browse files
committed
Ensure unique field names within a class, Closes #44
1 parent eb1cc3c commit 7c14d2a

2 files changed

Lines changed: 307 additions & 24 deletions

File tree

lib/serialize/ComponentConstructor.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,24 @@ export class ComponentConstructor {
178178
* @param context A parsed JSON-LD context.
179179
* @param classReference The class reference.
180180
* @param fieldName The name of the field.
181+
* @param scope The current field scope.
181182
*/
182-
public fieldNameToId(context: JsonLdContextNormalized, classReference: ClassReference, fieldName: string): string {
183-
return context.compactIri(`${this.packageMetadata.moduleIri}/${this.getPathRelative(classReference.fileName)}#${classReference.localName}_${fieldName}`);
183+
public fieldNameToId(
184+
context: JsonLdContextNormalized,
185+
classReference: ClassReference,
186+
fieldName: string,
187+
scope: FieldScope,
188+
): string {
189+
if (scope.parentFieldNames.length > 0) {
190+
fieldName = `${scope.parentFieldNames.join('_')}_${fieldName}`;
191+
}
192+
let id = context.compactIri(`${this.packageMetadata.moduleIri}/${this.getPathRelative(classReference.fileName)}#${classReference.localName}_${fieldName}`);
193+
if (id in scope.fieldIdsHash) {
194+
id += `_${scope.fieldIdsHash[id]++}`;
195+
} else {
196+
scope.fieldIdsHash[id] = 1;
197+
}
198+
return id;
184199
}
185200

186201
/**
@@ -198,12 +213,17 @@ export class ComponentConstructor {
198213
constructorData: ConstructorData<ParameterRangeResolved>,
199214
parameters: ParameterDefinition[],
200215
): ConstructorArgumentDefinition[] {
216+
const scope: FieldScope = {
217+
parentFieldNames: [],
218+
fieldIdsHash: {},
219+
};
201220
return constructorData.parameters.map(parameter => this.parameterDataToConstructorArgument(
202221
context,
203222
classReference,
204223
parameter,
205224
parameters,
206-
this.fieldNameToId(context, classReference, parameter.name),
225+
this.fieldNameToId(context, classReference, parameter.name, scope),
226+
scope,
207227
));
208228
}
209229

@@ -218,13 +238,15 @@ export class ComponentConstructor {
218238
* @param parameterData Parameter data.
219239
* @param parameters The array of parameters of the owning class, which will be appended to.
220240
* @param fieldId The @id of the field.
241+
* @param scope The current field scope.
221242
*/
222243
public parameterDataToConstructorArgument(
223244
context: JsonLdContextNormalized,
224245
classReference: ClassLoaded,
225246
parameterData: ParameterData<ParameterRangeResolved>,
226247
parameters: ParameterDefinition[],
227248
fieldId: string,
249+
scope: FieldScope,
228250
): ConstructorArgumentDefinition {
229251
if (parameterData.range.type === 'nested') {
230252
// Create a hash object with `fields` entries.
@@ -235,6 +257,7 @@ export class ComponentConstructor {
235257
<ParameterData<ParameterRangeResolved> & { range: { type: 'nested' } }> parameterData,
236258
parameters,
237259
subParamData,
260+
scope,
238261
));
239262
return { fields };
240263
}
@@ -257,23 +280,30 @@ export class ComponentConstructor {
257280
* @param parameterData Parameter data with nested range.
258281
* @param parameters The array of parameters of the owning class, which will be appended to.
259282
* @param subParamData The sub-parameter of the parameter with nested range.
283+
* @param scope The current field scope.
260284
*/
261285
public constructFieldDefinitionNested(
262286
context: JsonLdContextNormalized,
263287
classReference: ClassLoaded,
264288
parameterData: ParameterData<ParameterRangeResolved> & { range: { type: 'nested' } },
265289
parameters: ParameterDefinition[],
266290
subParamData: ParameterData<ParameterRangeResolved>,
291+
scope: FieldScope,
267292
): ConstructorFieldDefinition {
268293
if (subParamData.type === 'field') {
294+
const subScope: FieldScope = {
295+
parentFieldNames: [ ...scope.parentFieldNames, subParamData.name ],
296+
fieldIdsHash: scope.fieldIdsHash,
297+
};
269298
return {
270299
keyRaw: subParamData.name,
271300
value: this.parameterDataToConstructorArgument(
272301
context,
273302
classReference,
274303
subParamData,
275304
parameters,
276-
this.fieldNameToId(context, classReference, subParamData.name),
305+
this.fieldNameToId(context, classReference, subParamData.name, scope),
306+
subScope,
277307
),
278308
};
279309
}
@@ -287,9 +317,9 @@ export class ComponentConstructor {
287317
}
288318

289319
// Determine parameter id's
290-
const idCollectEntries = this.fieldNameToId(context, classReference, parameterData.name);
291-
const idKey = this.fieldNameToId(context, classReference, `${parameterData.name}_key`);
292-
const idValue = this.fieldNameToId(context, classReference, `${parameterData.name}_value`);
320+
const idCollectEntries = this.fieldNameToId(context, classReference, parameterData.name, scope);
321+
const idKey = this.fieldNameToId(context, classReference, `${parameterData.name}_key`, scope);
322+
const idValue = this.fieldNameToId(context, classReference, `${parameterData.name}_value`, scope);
293323

294324
// Create sub parameters for key and value
295325
const subParameters: ParameterDefinition[] = [];
@@ -304,6 +334,7 @@ export class ComponentConstructor {
304334
subParamData,
305335
subParameters,
306336
idValue,
337+
scope,
307338
);
308339
subParameters[subParameters.length - 1].required = true;
309340
subParameters[subParameters.length - 1].unique = true;
@@ -312,7 +343,7 @@ export class ComponentConstructor {
312343
const parameter: ParameterDefinition = {
313344
'@id': idCollectEntries,
314345
range: {
315-
'@type': this.fieldNameToId(context, classReference, `${parameterData.name}_range`),
346+
'@type': this.fieldNameToId(context, classReference, `${parameterData.name}_range`, scope),
316347
parameters: subParameters,
317348
},
318349
};
@@ -416,3 +447,14 @@ export interface PathDestinationDefinition {
416447
originalPath: string;
417448
replacementPath: string;
418449
}
450+
451+
export interface FieldScope {
452+
/**
453+
* All parent field names for the current scope.
454+
*/
455+
parentFieldNames: string[];
456+
/**
457+
* A hash containing all previously created field names, to ensure uniqueness.
458+
*/
459+
fieldIdsHash: {[fieldName: string]: number};
460+
}

0 commit comments

Comments
 (0)