convention_builder 1.4.3 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8614,7 +8614,12 @@ var require_schema_utilities = __commonJS({
8614
8614
  __name(apiComposeTaxonomiesTransformation, "apiComposeTaxonomiesTransformation");
8615
8615
  function exampleImporter(filename, basePath = `${__dirname}/../../../definitions/examples/raw_examples_and_scripts/`, schemataSource = `${__dirname}/../../../input/collection`) {
8616
8616
  let rawData = JSON.parse(fs.readFileSync(`${basePath}/${filename}`)).map((obj) => {
8617
- let output = obj.entity;
8617
+ let output = obj.entity ? obj.entity : obj;
8618
+ if (!output) {
8619
+ console.log(obj);
8620
+ console.log(output);
8621
+ }
8622
+ ;
8618
8623
  if (output.attributes.relationships) {
8619
8624
  output.relationships = output.attributes.relationships;
8620
8625
  delete output.attributes.relationships;
@@ -8631,7 +8636,7 @@ var require_schema_utilities = __commonJS({
8631
8636
  });
8632
8637
  let newEntities = [];
8633
8638
  let entities = rawData.flatMap((entity) => {
8634
- let transformedData = apiComposeTaxonomiesTransformation(entity);
8639
+ let transformedData = entity.relationships ? apiComposeTaxonomiesTransformation(entity) : { mainEntity: entity, newEntities: [] };
8635
8640
  return [transformedData.mainEntity, ...transformedData.newEntities];
8636
8641
  });
8637
8642
  return entities;
@@ -9052,6 +9057,20 @@ var require_schema_utilities = __commonJS({
9052
9057
  return output;
9053
9058
  }
9054
9059
  __name(findAllNonObjectAttributesInTree, "findAllNonObjectAttributesInTree");
9060
+ function gitlabConventionURLTemplate({ conventionName, projectID }) {
9061
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/output/collection/conventions/${conventionName}/schema.json?job=copy_schemas`;
9062
+ }
9063
+ __name(gitlabConventionURLTemplate, "gitlabConventionURLTemplate");
9064
+ function gitlabOverlayURLTemplate({ overlayName, projectID, baseEntityTypeAndbundle = "" }) {
9065
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/input/collection/${overlayName}/schema.json?job=copy_schemas`;
9066
+ }
9067
+ __name(gitlabOverlayURLTemplate, "gitlabOverlayURLTemplate");
9068
+ function basicSchemaURLTemplate({ baseEntityTypeAndBundle, projectID }) {
9069
+ let type = baseEntityTypeAndBundle.split("--")[0];
9070
+ let bundle = baseEntityTypeAndBundle.split("--")[1];
9071
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/input/collection/${type}/${bundle}/schema.json?job=copy_schemas`;
9072
+ }
9073
+ __name(basicSchemaURLTemplate, "basicSchemaURLTemplate");
9055
9074
  exports.dig = dig;
9056
9075
  exports.bury = bury;
9057
9076
  exports.fixRelationshipDataField = fixRelationshipDataField;
@@ -9074,6 +9093,9 @@ var require_schema_utilities = __commonJS({
9074
9093
  exports.listAttributesAndSubAttributes = listAttributesAndSubAttributes;
9075
9094
  exports.findAllObjectAttributesInTree = findAllObjectAttributesInTree;
9076
9095
  exports.findAllNonObjectAttributesInTree = findAllNonObjectAttributesInTree;
9096
+ exports.gitlabConventionURLTemplate = gitlabConventionURLTemplate;
9097
+ exports.gitlabOverlayURLTemplate = gitlabOverlayURLTemplate;
9098
+ exports.basicSchemaURLTemplate = basicSchemaURLTemplate;
9077
9099
  }
9078
9100
  });
9079
9101
 
@@ -9088,7 +9110,11 @@ var require_convention_builder = __commonJS({
9088
9110
  bury,
9089
9111
  listAttributesAndSubAttributes,
9090
9112
  findAllObjectAttributesInTree,
9091
- findAllNonObjectAttributesInTree
9113
+ findAllNonObjectAttributesInTree,
9114
+ gitlabOverlayURLTemplate,
9115
+ gitlabConventionURLTemplate,
9116
+ basicSchemaURLTemplate,
9117
+ arrayToStructuredConvention
9092
9118
  } = require_schema_utilities();
9093
9119
  function getAttributes(root, convention) {
9094
9120
  let branches = convention.relationships.filter((rel) => rel.containerEntity == root).map((d) => d.mentionedEntity);
@@ -9103,21 +9129,23 @@ var require_convention_builder = __commonJS({
9103
9129
  name,
9104
9130
  validExamples,
9105
9131
  erroredExamples,
9106
- repoURL,
9132
+ repoURLTemplateFunction = gitlabOverlayURLTemplate,
9107
9133
  storageFolder = `${__dirname}/../../../../output/collection/overlays`,
9108
9134
  strictEnums = true,
9109
9135
  overlay = false,
9110
9136
  originalSrcScript,
9111
9137
  trivial = false,
9112
9138
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9139
+ gitlabProjectId = process.env.CI_PROJECT_ID,
9113
9140
  requiredFields = [],
9114
- modifiedAttributes
9141
+ modifiedAttributes,
9142
+ deletedAttributes = []
9115
9143
  }) {
9116
9144
  this.name = name;
9117
9145
  this.typeAndBundle = typeAndBundle;
9118
9146
  this.validExamples = validExamples;
9119
9147
  this.erroredExamples = erroredExamples;
9120
- this.repoURL = repoURL;
9148
+ this.repoURLTemplateFunction = repoURLTemplateFunction;
9121
9149
  this.schemaName = `${typeAndBundle}--${name}`;
9122
9150
  this.storageFolder = storageFolder;
9123
9151
  this.strictEnums = strictEnums;
@@ -9147,6 +9175,7 @@ var require_convention_builder = __commonJS({
9147
9175
  this.baseSchema = baseSchema;
9148
9176
  this.unmodifiedAttributes = listAttributesAndSubAttributes(this.baseSchema);
9149
9177
  this.modifiedAttributes = modifiedAttributes ? modifiedAttributes : /* @__PURE__ */ new Set([]);
9178
+ this.deletedAttributes = deletedAttributes;
9150
9179
  if (!overlay) {
9151
9180
  this.overlay = {
9152
9181
  properties: {
@@ -9178,8 +9207,8 @@ var require_convention_builder = __commonJS({
9178
9207
  */
9179
9208
  updateSchema() {
9180
9209
  this.schema = {};
9181
- this.schema.$id = `${this.repoURL}/schemata/${this.typeAndBundle.replace("--", "/")}/schema.json`;
9182
9210
  Object.assign(this.schema, this.baseSchema);
9211
+ this.schema.$id = this.repoURLTemplateFunction({ overlayName: this.name, projectID: this.gitlabProjectId, baseEntityTypeAndBundle: this.typeAndBundle });
9183
9212
  let allModifiedAttributes = listAttributesAndSubAttributes(this.overlay);
9184
9213
  this.modifiedAttributes = allModifiedAttributes;
9185
9214
  this.unmodifiedAttributes = listAttributesAndSubAttributes(this.baseSchema);
@@ -9188,6 +9217,7 @@ var require_convention_builder = __commonJS({
9188
9217
  let currentValue = dig(this.overlay.properties.attributes.properties, attr);
9189
9218
  bury(this.schema, `properties.attributes.properties.${attr}`, currentValue, false);
9190
9219
  });
9220
+ this.deletedAttributes.forEach((deletedAttr) => delete this.schema.properties.attributes.properties[deletedAttr]);
9191
9221
  let originalRequiredFields = this.schema.properties.attributes.required ? this.schema.properties.attributes.required : [];
9192
9222
  let allRequiredSet = Array.from(/* @__PURE__ */ new Set([...originalRequiredFields, ...Array.from(this.requiredFields)]));
9193
9223
  this.schema.properties.attributes.required = allRequiredSet;
@@ -9290,6 +9320,15 @@ var require_convention_builder = __commonJS({
9290
9320
  ;
9291
9321
  this.setGenericSection({ attribute, section: subschema, description });
9292
9322
  }
9323
+ /**
9324
+ * Mark an attribute to be omitted from the resulting schema.
9325
+ * @param {} attribute
9326
+ */
9327
+ deleteAttribute(attribute) {
9328
+ this.deletedAttributes.push(attribute);
9329
+ delete this.overlay.properties.attributes.properties[attribute];
9330
+ this.updateAttributeStatus(attribute);
9331
+ }
9293
9332
  /**
9294
9333
  * Build an AJV validator and ensure all valid examples are accepted and all error examples are rejected. Returns an array attribute for each set of examples, plus a general success attribute indicating wether all examples resulted as expected and a failedExamples array only listing entities for which there was no success (meanin unrejected error examples and rejected valid examples).
9295
9334
  */
@@ -9380,16 +9419,18 @@ var require_convention_builder = __commonJS({
9380
9419
  constructor({
9381
9420
  typeAndBundle,
9382
9421
  attributeOverlayName,
9383
- repoURL,
9422
+ repoURLTemplateFunction = basicSchemaURLTemplate,
9384
9423
  strictEnums = true,
9385
- baseSchemataFolder = `${__dirname}/../../../../input/collection`
9424
+ baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9425
+ gitlabProjectId = process.env.CI_PROJECT_ID
9386
9426
  }) {
9387
9427
  super({
9388
9428
  typeAndBundle,
9389
- repoURL,
9429
+ repoURLTemplateFunction,
9390
9430
  storageFolder: baseSchemataFolder,
9391
9431
  baseSchemataFolder,
9392
- strictEnums
9432
+ strictEnums,
9433
+ gitlabProjectId
9393
9434
  });
9394
9435
  this.attributeOverlayName = attributeOverlayName;
9395
9436
  }
@@ -9417,12 +9458,13 @@ var require_convention_builder = __commonJS({
9417
9458
  title,
9418
9459
  schemaName,
9419
9460
  version,
9420
- repoURL,
9461
+ repoURLTemplateFunction = gitlabConventionURLTemplate,
9421
9462
  description,
9422
- validExamples,
9423
- erroredExamples,
9463
+ validExamples = [],
9464
+ erroredExamples = [],
9424
9465
  storageFolder = `${__dirname}/../../../../output/collection`,
9425
9466
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9467
+ gitlabProjectId = process.env.CI_PROJECT_ID,
9426
9468
  strictEnums = false,
9427
9469
  overlays = false,
9428
9470
  relationships = false,
@@ -9437,13 +9479,14 @@ var require_convention_builder = __commonJS({
9437
9479
  this.description = description;
9438
9480
  this.schemaName = schemaName;
9439
9481
  this.version = version;
9440
- this.repoURL = repoURL, this.validExamples = validExamples;
9482
+ this.repoURLTemplateFunction = repoURLTemplateFunction, this.validExamples = validExamples;
9441
9483
  this.erroredExamples = erroredExamples;
9442
9484
  this.overlays = {};
9443
9485
  this.relationships = [];
9444
9486
  this.required = [];
9445
9487
  this.storageFolder = storageFolder;
9446
9488
  this.baseSchemataFolder = baseSchemataFolder;
9489
+ this.gitlabProjectId = gitlabProjectId;
9447
9490
  if (overlays) {
9448
9491
  let overlayNames = Object.keys(overlays);
9449
9492
  this.overlays = {};
@@ -9519,7 +9562,7 @@ var require_convention_builder = __commonJS({
9519
9562
  this.schema = {
9520
9563
  title: this.title,
9521
9564
  type: "object",
9522
- $id: `${this.repoURL}/${this.version}/conventions/${this.schemaName}`,
9565
+ $id: this.repoURLTemplateFunction({ conventionName: this.schemaName, projectID: this.gitlabProjectId }),
9523
9566
  $schema: "https://json-schema.org/draft/2020-12/schema",
9524
9567
  properties: {},
9525
9568
  description: this.description,
@@ -9744,17 +9787,102 @@ import TabItem from '@theme/TabItem';
9744
9787
  let body = [header, mainText, "# View Schema\n", "<Tabs>", schemaPluginInvocation, schemaPluginInvocationRequiredOnly, codeBlock, conventionAsText, "</Tabs>"].join("\n");
9745
9788
  return body;
9746
9789
  }
9790
+ getExamplesFromFile({ path }) {
9791
+ let isFolder = fs.lstatSync(path).isDirectory();
9792
+ let isJSONFile = new RegExp(/\.json$/i).test(path);
9793
+ let noFilesError = `The provided path (${path}) does not lead to JSON file nor a folder containing JSON files. Folder: ${isFolder}, JSON File: ${isJSONFile}`;
9794
+ let output = [];
9795
+ if (isFolder) {
9796
+ let folderExamples = fs.readdirSync(path, (error, files) => {
9797
+ return files;
9798
+ }).filter((path2) => new RegExp(/\.json$/i).test(path2)).map((filename) => {
9799
+ let examples = JSON.parse(fs.readFileSync(`${path}/${filename}`));
9800
+ return examples;
9801
+ });
9802
+ if (folderExamples.length == 0) {
9803
+ throw new Error(noFilesError);
9804
+ }
9805
+ ;
9806
+ output.push(...folderExamples);
9807
+ } else if (isJSONFile) {
9808
+ let example = JSON.parse(fs.readFileSync(path));
9809
+ output.push(example);
9810
+ } else {
9811
+ throw new Error(noFilesError);
9812
+ }
9813
+ ;
9814
+ return output;
9815
+ }
9816
+ /**
9817
+ * Will retrieve an individual example from a JSON file or all examples in a given folder. They all need to be either valid or invalid examples, and that should be indicated by the 'is_valid_example' attribute.
9818
+ * @param {string} path -- A string representing an absolute path, leading to either a JSON file containing an individual example or a folder containing several examples.
9819
+ * @param {object|array} object -- Either an array of examples or an individual example.
9820
+ * @param {boolean} is_valid_example -- Whether to store the provided examples as valid examples or errors, for the tests.
9821
+ * @param {boolean} structured_as_array -- Mark as "true" if the provided example is structured as a loose array of entities, as FarmOS delivers them (instead of structured as a convention object in which every entity is a property). The method will try to structure the entity and return meaningful information if it is not successful in doing so.
9822
+ */
9823
+ addExample({ path, object, is_valid_example, structured_as_array }) {
9824
+ let output = {
9825
+ success: false,
9826
+ errors: []
9827
+ };
9828
+ if (!path && !object) {
9829
+ throw new Error(`Either an object or a path leading to a folder or a json file need to be provided. Both arguments are empty.`);
9830
+ }
9831
+ ;
9832
+ let newExamples = [];
9833
+ if (object) {
9834
+ if (!Array.isArray(object)) {
9835
+ newExamples.push(object);
9836
+ } else {
9837
+ newExamples.push(...object);
9838
+ }
9839
+ ;
9840
+ } else if (path) {
9841
+ newExamples = this.getExamplesFromFile({ path });
9842
+ }
9843
+ ;
9844
+ if (structured_as_array) {
9845
+ newExamples = newExamples.map((exampleArray) => {
9846
+ let exampleObject = arrayToStructuredConvention({
9847
+ entitiesArray: exampleArray,
9848
+ conventionObject: this
9849
+ });
9850
+ if (!exampleObject.is_valid && is_valid_example) {
9851
+ output.errors.push("The `arrayToStructuredConvention` function wasn't able to rebuild a valid instance of this convention's schema from the provided array of loose entities. Look into the '.structuringAttempt' attribute for more information.");
9852
+ }
9853
+ ;
9854
+ if (!is_valid_example) {
9855
+ output.warning = "Since the example is not marked as 'valid', we can't check it is being properly parsed. Please review the output 'assembled_entity' to check it looks as it should.";
9856
+ }
9857
+ ;
9858
+ output.structuringAttempt = exampleObject;
9859
+ return exampleObject.assembled_entity;
9860
+ });
9861
+ }
9862
+ ;
9863
+ if (is_valid_example) {
9864
+ this.validExamples.push(...newExamples);
9865
+ } else {
9866
+ this.erroredExamples.push(...newExamples);
9867
+ }
9868
+ ;
9869
+ if (output.errors.length == 0) {
9870
+ output.success = true;
9871
+ }
9872
+ ;
9873
+ return output;
9874
+ }
9747
9875
  /**
9748
9876
  * Build an AJV validator and ensure all valid examples are accepted and all error examples are rejected. Returns an array attribute for each set of examples, plus a general success attribute indicating wether all examples resulted as expected and a failedExamples array only listing entities for which there was no success (meanin unrejected error examples and rejected valid examples).
9749
9877
  */
9750
9878
  testExamples() {
9751
9879
  let generalOutput = {};
9752
9880
  if (!this.validExamples || !this.erroredExamples) {
9753
- throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute`);
9881
+ throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute. Valid examples amount: ${this.validExamples ? this.validExamples.length : "validExamples is not an array"}, errored examples amount: ${this.erroredExamples ? this.erroredExamples.length : "erroredExamples is not an array"}.`);
9754
9882
  }
9755
9883
  ;
9756
9884
  if (this.validExamples.length == 0 || this.erroredExamples.length == 0) {
9757
- throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute`);
9885
+ throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute. Valid examples amount: ${this.validExamples ? this.validExamples.length : "validExamples is not an array"}, errored examples amount: ${this.erroredExamples ? this.erroredExamples.length : "erroredExamples is not an array"}.`);
9758
9886
  }
9759
9887
  ;
9760
9888
  this.updateSchema();
@@ -9860,7 +9988,7 @@ import TabItem from '@theme/TabItem';
9860
9988
  };
9861
9989
  __name(_ConventionSchema, "ConventionSchema");
9862
9990
  var ConventionSchema = _ConventionSchema;
9863
- var _AttributeOverlay = class _AttributeOverlay {
9991
+ var _InputConventionChanges = class _InputConventionChanges {
9864
9992
  constructor({
9865
9993
  type,
9866
9994
  bundle,
@@ -9868,7 +9996,8 @@ import TabItem from '@theme/TabItem';
9868
9996
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9869
9997
  sourceSchemataFile = `${__dirname}/../../../../input/farmos.json`,
9870
9998
  overlayName,
9871
- overlayDescription
9999
+ overlayDescription,
10000
+ gitlabProjectId = process.env.CI_PROJECT_ID
9872
10001
  }) {
9873
10002
  let integralSchemataFile = JSON.parse(fs.readFileSync(sourceSchemataFile));
9874
10003
  this.type = type;
@@ -9879,6 +10008,7 @@ import TabItem from '@theme/TabItem';
9879
10008
  this.sourceSchemata = integralSchemataFile;
9880
10009
  this.lexicon = [...findAllObjectAttributesInTree(this.sourceSchemata), ...findAllNonObjectAttributesInTree(this.sourceSchemata)];
9881
10010
  this.baseSchemataFolder = baseSchemataFolder;
10011
+ this.gitlabProjectId = gitlabProjectId;
9882
10012
  let involvedSchemata = this.lexicon.filter((entry) => this.attribute == entry.attribute).flatMap((entry) => entry.instances).filter((instance) => this.type ? instance.type == this.type : true).filter((instance) => this.bundle ? instance.bundle == this.bundle : true).map((d) => d.schema);
9883
10013
  this.targetSchemata = Array.from(new Set(involvedSchemata));
9884
10014
  this.overlays = [];
@@ -9886,8 +10016,10 @@ import TabItem from '@theme/TabItem';
9886
10016
  let currentOverlay = new AttributePatchingSchemaOverlay({
9887
10017
  typeAndBundle: target,
9888
10018
  attributeOverlayName: this.overlayName,
9889
- baseSchemataFolder: this.baseSchemataFolder
10019
+ baseSchemataFolder: this.baseSchemataFolder,
10020
+ gitlabProjectId: this.gitlabProjectId
9890
10021
  });
10022
+ currentOverlay.gitlabProjectId = this.gitlabProjectId;
9891
10023
  this.overlays.push(currentOverlay);
9892
10024
  });
9893
10025
  }
@@ -9948,6 +10080,15 @@ import TabItem from '@theme/TabItem';
9948
10080
  });
9949
10081
  });
9950
10082
  }
10083
+ /**
10084
+ * Mark an attribute to be omitted from the resulting schema.
10085
+ * @param {} attribute
10086
+ */
10087
+ deleteAttribute() {
10088
+ this.overlays.forEach((overlay) => {
10089
+ overlay.deleteAttribute(this.attribute);
10090
+ });
10091
+ }
9951
10092
  /**
9952
10093
  * Stores all involved schemas into the folder structure for `base schemata` (provided as the parameter `baseSchemataFolder`) which will be consumed by our conventions later.
9953
10094
  * @returns {} -- It returns objects containing all paths.
@@ -9960,21 +10101,21 @@ import TabItem from '@theme/TabItem';
9960
10101
  return output;
9961
10102
  }
9962
10103
  };
9963
- __name(_AttributeOverlay, "AttributeOverlay");
9964
- var AttributeOverlay = _AttributeOverlay;
10104
+ __name(_InputConventionChanges, "InputConventionChanges");
10105
+ var InputConventionChanges = _InputConventionChanges;
9965
10106
  exports.SchemaOverlay = SchemaOverlay;
9966
10107
  exports.ConventionSchema = ConventionSchema;
9967
- exports.AttributeOverlay = AttributeOverlay;
10108
+ exports.InputConventionChanges = InputConventionChanges;
9968
10109
  }
9969
10110
  });
9970
10111
 
9971
10112
  // src/index.js
9972
10113
  var require_src = __commonJS({
9973
10114
  "src/index.js"(exports) {
9974
- var { SchemaOverlay, ConventionSchema, AttributeOverlay } = require_convention_builder();
10115
+ var { SchemaOverlay, ConventionSchema, InputConventionChanges } = require_convention_builder();
9975
10116
  var schemaUtils = require_schema_utilities();
9976
10117
  exports.SchemaOverlay = SchemaOverlay;
9977
- exports.AttributeOverlay = AttributeOverlay;
10118
+ exports.InputConventionChanges = InputConventionChanges;
9978
10119
  exports.ConventionSchema = ConventionSchema;
9979
10120
  exports.fixRelationshipDataField = schemaUtils.fixRelationshipDataField;
9980
10121
  exports.buildValidator = schemaUtils.buildValidator;
@@ -8607,7 +8607,12 @@ var require_schema_utilities = __commonJS({
8607
8607
  __name(apiComposeTaxonomiesTransformation, "apiComposeTaxonomiesTransformation");
8608
8608
  function exampleImporter(filename, basePath = `${__dirname}/../../../definitions/examples/raw_examples_and_scripts/`, schemataSource = `${__dirname}/../../../input/collection`) {
8609
8609
  let rawData = JSON.parse(fs.readFileSync(`${basePath}/${filename}`)).map((obj) => {
8610
- let output = obj.entity;
8610
+ let output = obj.entity ? obj.entity : obj;
8611
+ if (!output) {
8612
+ console.log(obj);
8613
+ console.log(output);
8614
+ }
8615
+ ;
8611
8616
  if (output.attributes.relationships) {
8612
8617
  output.relationships = output.attributes.relationships;
8613
8618
  delete output.attributes.relationships;
@@ -8624,7 +8629,7 @@ var require_schema_utilities = __commonJS({
8624
8629
  });
8625
8630
  let newEntities = [];
8626
8631
  let entities = rawData.flatMap((entity) => {
8627
- let transformedData = apiComposeTaxonomiesTransformation(entity);
8632
+ let transformedData = entity.relationships ? apiComposeTaxonomiesTransformation(entity) : { mainEntity: entity, newEntities: [] };
8628
8633
  return [transformedData.mainEntity, ...transformedData.newEntities];
8629
8634
  });
8630
8635
  return entities;
@@ -9045,6 +9050,20 @@ var require_schema_utilities = __commonJS({
9045
9050
  return output;
9046
9051
  }
9047
9052
  __name(findAllNonObjectAttributesInTree, "findAllNonObjectAttributesInTree");
9053
+ function gitlabConventionURLTemplate({ conventionName, projectID }) {
9054
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/output/collection/conventions/${conventionName}/schema.json?job=copy_schemas`;
9055
+ }
9056
+ __name(gitlabConventionURLTemplate, "gitlabConventionURLTemplate");
9057
+ function gitlabOverlayURLTemplate({ overlayName, projectID, baseEntityTypeAndbundle = "" }) {
9058
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/input/collection/${overlayName}/schema.json?job=copy_schemas`;
9059
+ }
9060
+ __name(gitlabOverlayURLTemplate, "gitlabOverlayURLTemplate");
9061
+ function basicSchemaURLTemplate({ baseEntityTypeAndBundle, projectID }) {
9062
+ let type = baseEntityTypeAndBundle.split("--")[0];
9063
+ let bundle = baseEntityTypeAndBundle.split("--")[1];
9064
+ return `https://gitlab.com/api/v4/projects/${projectID}/jobs/artifacts/main/raw/input/collection/${type}/${bundle}/schema.json?job=copy_schemas`;
9065
+ }
9066
+ __name(basicSchemaURLTemplate, "basicSchemaURLTemplate");
9048
9067
  exports2.dig = dig;
9049
9068
  exports2.bury = bury;
9050
9069
  exports2.fixRelationshipDataField = fixRelationshipDataField;
@@ -9067,6 +9086,9 @@ var require_schema_utilities = __commonJS({
9067
9086
  exports2.listAttributesAndSubAttributes = listAttributesAndSubAttributes;
9068
9087
  exports2.findAllObjectAttributesInTree = findAllObjectAttributesInTree;
9069
9088
  exports2.findAllNonObjectAttributesInTree = findAllNonObjectAttributesInTree;
9089
+ exports2.gitlabConventionURLTemplate = gitlabConventionURLTemplate;
9090
+ exports2.gitlabOverlayURLTemplate = gitlabOverlayURLTemplate;
9091
+ exports2.basicSchemaURLTemplate = basicSchemaURLTemplate;
9070
9092
  }
9071
9093
  });
9072
9094
 
@@ -9081,7 +9103,11 @@ var require_convention_builder = __commonJS({
9081
9103
  bury,
9082
9104
  listAttributesAndSubAttributes,
9083
9105
  findAllObjectAttributesInTree,
9084
- findAllNonObjectAttributesInTree
9106
+ findAllNonObjectAttributesInTree,
9107
+ gitlabOverlayURLTemplate,
9108
+ gitlabConventionURLTemplate,
9109
+ basicSchemaURLTemplate,
9110
+ arrayToStructuredConvention
9085
9111
  } = require_schema_utilities();
9086
9112
  function getAttributes(root, convention) {
9087
9113
  let branches = convention.relationships.filter((rel) => rel.containerEntity == root).map((d) => d.mentionedEntity);
@@ -9096,21 +9122,23 @@ var require_convention_builder = __commonJS({
9096
9122
  name,
9097
9123
  validExamples,
9098
9124
  erroredExamples,
9099
- repoURL,
9125
+ repoURLTemplateFunction = gitlabOverlayURLTemplate,
9100
9126
  storageFolder = `${__dirname}/../../../../output/collection/overlays`,
9101
9127
  strictEnums = true,
9102
9128
  overlay = false,
9103
9129
  originalSrcScript,
9104
9130
  trivial = false,
9105
9131
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9132
+ gitlabProjectId = process.env.CI_PROJECT_ID,
9106
9133
  requiredFields = [],
9107
- modifiedAttributes
9134
+ modifiedAttributes,
9135
+ deletedAttributes = []
9108
9136
  }) {
9109
9137
  this.name = name;
9110
9138
  this.typeAndBundle = typeAndBundle;
9111
9139
  this.validExamples = validExamples;
9112
9140
  this.erroredExamples = erroredExamples;
9113
- this.repoURL = repoURL;
9141
+ this.repoURLTemplateFunction = repoURLTemplateFunction;
9114
9142
  this.schemaName = `${typeAndBundle}--${name}`;
9115
9143
  this.storageFolder = storageFolder;
9116
9144
  this.strictEnums = strictEnums;
@@ -9140,6 +9168,7 @@ var require_convention_builder = __commonJS({
9140
9168
  this.baseSchema = baseSchema;
9141
9169
  this.unmodifiedAttributes = listAttributesAndSubAttributes(this.baseSchema);
9142
9170
  this.modifiedAttributes = modifiedAttributes ? modifiedAttributes : /* @__PURE__ */ new Set([]);
9171
+ this.deletedAttributes = deletedAttributes;
9143
9172
  if (!overlay) {
9144
9173
  this.overlay = {
9145
9174
  properties: {
@@ -9171,8 +9200,8 @@ var require_convention_builder = __commonJS({
9171
9200
  */
9172
9201
  updateSchema() {
9173
9202
  this.schema = {};
9174
- this.schema.$id = `${this.repoURL}/schemata/${this.typeAndBundle.replace("--", "/")}/schema.json`;
9175
9203
  Object.assign(this.schema, this.baseSchema);
9204
+ this.schema.$id = this.repoURLTemplateFunction({ overlayName: this.name, projectID: this.gitlabProjectId, baseEntityTypeAndBundle: this.typeAndBundle });
9176
9205
  let allModifiedAttributes = listAttributesAndSubAttributes(this.overlay);
9177
9206
  this.modifiedAttributes = allModifiedAttributes;
9178
9207
  this.unmodifiedAttributes = listAttributesAndSubAttributes(this.baseSchema);
@@ -9181,6 +9210,7 @@ var require_convention_builder = __commonJS({
9181
9210
  let currentValue = dig(this.overlay.properties.attributes.properties, attr);
9182
9211
  bury(this.schema, `properties.attributes.properties.${attr}`, currentValue, false);
9183
9212
  });
9213
+ this.deletedAttributes.forEach((deletedAttr) => delete this.schema.properties.attributes.properties[deletedAttr]);
9184
9214
  let originalRequiredFields = this.schema.properties.attributes.required ? this.schema.properties.attributes.required : [];
9185
9215
  let allRequiredSet = Array.from(/* @__PURE__ */ new Set([...originalRequiredFields, ...Array.from(this.requiredFields)]));
9186
9216
  this.schema.properties.attributes.required = allRequiredSet;
@@ -9283,6 +9313,15 @@ var require_convention_builder = __commonJS({
9283
9313
  ;
9284
9314
  this.setGenericSection({ attribute, section: subschema, description });
9285
9315
  }
9316
+ /**
9317
+ * Mark an attribute to be omitted from the resulting schema.
9318
+ * @param {} attribute
9319
+ */
9320
+ deleteAttribute(attribute) {
9321
+ this.deletedAttributes.push(attribute);
9322
+ delete this.overlay.properties.attributes.properties[attribute];
9323
+ this.updateAttributeStatus(attribute);
9324
+ }
9286
9325
  /**
9287
9326
  * Build an AJV validator and ensure all valid examples are accepted and all error examples are rejected. Returns an array attribute for each set of examples, plus a general success attribute indicating wether all examples resulted as expected and a failedExamples array only listing entities for which there was no success (meanin unrejected error examples and rejected valid examples).
9288
9327
  */
@@ -9373,16 +9412,18 @@ var require_convention_builder = __commonJS({
9373
9412
  constructor({
9374
9413
  typeAndBundle,
9375
9414
  attributeOverlayName,
9376
- repoURL,
9415
+ repoURLTemplateFunction = basicSchemaURLTemplate,
9377
9416
  strictEnums = true,
9378
- baseSchemataFolder = `${__dirname}/../../../../input/collection`
9417
+ baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9418
+ gitlabProjectId = process.env.CI_PROJECT_ID
9379
9419
  }) {
9380
9420
  super({
9381
9421
  typeAndBundle,
9382
- repoURL,
9422
+ repoURLTemplateFunction,
9383
9423
  storageFolder: baseSchemataFolder,
9384
9424
  baseSchemataFolder,
9385
- strictEnums
9425
+ strictEnums,
9426
+ gitlabProjectId
9386
9427
  });
9387
9428
  this.attributeOverlayName = attributeOverlayName;
9388
9429
  }
@@ -9410,12 +9451,13 @@ var require_convention_builder = __commonJS({
9410
9451
  title,
9411
9452
  schemaName,
9412
9453
  version,
9413
- repoURL,
9454
+ repoURLTemplateFunction = gitlabConventionURLTemplate,
9414
9455
  description,
9415
- validExamples,
9416
- erroredExamples,
9456
+ validExamples = [],
9457
+ erroredExamples = [],
9417
9458
  storageFolder = `${__dirname}/../../../../output/collection`,
9418
9459
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9460
+ gitlabProjectId = process.env.CI_PROJECT_ID,
9419
9461
  strictEnums = false,
9420
9462
  overlays = false,
9421
9463
  relationships = false,
@@ -9430,13 +9472,14 @@ var require_convention_builder = __commonJS({
9430
9472
  this.description = description;
9431
9473
  this.schemaName = schemaName;
9432
9474
  this.version = version;
9433
- this.repoURL = repoURL, this.validExamples = validExamples;
9475
+ this.repoURLTemplateFunction = repoURLTemplateFunction, this.validExamples = validExamples;
9434
9476
  this.erroredExamples = erroredExamples;
9435
9477
  this.overlays = {};
9436
9478
  this.relationships = [];
9437
9479
  this.required = [];
9438
9480
  this.storageFolder = storageFolder;
9439
9481
  this.baseSchemataFolder = baseSchemataFolder;
9482
+ this.gitlabProjectId = gitlabProjectId;
9440
9483
  if (overlays) {
9441
9484
  let overlayNames = Object.keys(overlays);
9442
9485
  this.overlays = {};
@@ -9512,7 +9555,7 @@ var require_convention_builder = __commonJS({
9512
9555
  this.schema = {
9513
9556
  title: this.title,
9514
9557
  type: "object",
9515
- $id: `${this.repoURL}/${this.version}/conventions/${this.schemaName}`,
9558
+ $id: this.repoURLTemplateFunction({ conventionName: this.schemaName, projectID: this.gitlabProjectId }),
9516
9559
  $schema: "https://json-schema.org/draft/2020-12/schema",
9517
9560
  properties: {},
9518
9561
  description: this.description,
@@ -9737,17 +9780,102 @@ import TabItem from '@theme/TabItem';
9737
9780
  let body = [header, mainText, "# View Schema\n", "<Tabs>", schemaPluginInvocation, schemaPluginInvocationRequiredOnly, codeBlock, conventionAsText, "</Tabs>"].join("\n");
9738
9781
  return body;
9739
9782
  }
9783
+ getExamplesFromFile({ path }) {
9784
+ let isFolder = fs.lstatSync(path).isDirectory();
9785
+ let isJSONFile = new RegExp(/\.json$/i).test(path);
9786
+ let noFilesError = `The provided path (${path}) does not lead to JSON file nor a folder containing JSON files. Folder: ${isFolder}, JSON File: ${isJSONFile}`;
9787
+ let output = [];
9788
+ if (isFolder) {
9789
+ let folderExamples = fs.readdirSync(path, (error, files) => {
9790
+ return files;
9791
+ }).filter((path2) => new RegExp(/\.json$/i).test(path2)).map((filename) => {
9792
+ let examples = JSON.parse(fs.readFileSync(`${path}/${filename}`));
9793
+ return examples;
9794
+ });
9795
+ if (folderExamples.length == 0) {
9796
+ throw new Error(noFilesError);
9797
+ }
9798
+ ;
9799
+ output.push(...folderExamples);
9800
+ } else if (isJSONFile) {
9801
+ let example = JSON.parse(fs.readFileSync(path));
9802
+ output.push(example);
9803
+ } else {
9804
+ throw new Error(noFilesError);
9805
+ }
9806
+ ;
9807
+ return output;
9808
+ }
9809
+ /**
9810
+ * Will retrieve an individual example from a JSON file or all examples in a given folder. They all need to be either valid or invalid examples, and that should be indicated by the 'is_valid_example' attribute.
9811
+ * @param {string} path -- A string representing an absolute path, leading to either a JSON file containing an individual example or a folder containing several examples.
9812
+ * @param {object|array} object -- Either an array of examples or an individual example.
9813
+ * @param {boolean} is_valid_example -- Whether to store the provided examples as valid examples or errors, for the tests.
9814
+ * @param {boolean} structured_as_array -- Mark as "true" if the provided example is structured as a loose array of entities, as FarmOS delivers them (instead of structured as a convention object in which every entity is a property). The method will try to structure the entity and return meaningful information if it is not successful in doing so.
9815
+ */
9816
+ addExample({ path, object, is_valid_example, structured_as_array }) {
9817
+ let output = {
9818
+ success: false,
9819
+ errors: []
9820
+ };
9821
+ if (!path && !object) {
9822
+ throw new Error(`Either an object or a path leading to a folder or a json file need to be provided. Both arguments are empty.`);
9823
+ }
9824
+ ;
9825
+ let newExamples = [];
9826
+ if (object) {
9827
+ if (!Array.isArray(object)) {
9828
+ newExamples.push(object);
9829
+ } else {
9830
+ newExamples.push(...object);
9831
+ }
9832
+ ;
9833
+ } else if (path) {
9834
+ newExamples = this.getExamplesFromFile({ path });
9835
+ }
9836
+ ;
9837
+ if (structured_as_array) {
9838
+ newExamples = newExamples.map((exampleArray) => {
9839
+ let exampleObject = arrayToStructuredConvention({
9840
+ entitiesArray: exampleArray,
9841
+ conventionObject: this
9842
+ });
9843
+ if (!exampleObject.is_valid && is_valid_example) {
9844
+ output.errors.push("The `arrayToStructuredConvention` function wasn't able to rebuild a valid instance of this convention's schema from the provided array of loose entities. Look into the '.structuringAttempt' attribute for more information.");
9845
+ }
9846
+ ;
9847
+ if (!is_valid_example) {
9848
+ output.warning = "Since the example is not marked as 'valid', we can't check it is being properly parsed. Please review the output 'assembled_entity' to check it looks as it should.";
9849
+ }
9850
+ ;
9851
+ output.structuringAttempt = exampleObject;
9852
+ return exampleObject.assembled_entity;
9853
+ });
9854
+ }
9855
+ ;
9856
+ if (is_valid_example) {
9857
+ this.validExamples.push(...newExamples);
9858
+ } else {
9859
+ this.erroredExamples.push(...newExamples);
9860
+ }
9861
+ ;
9862
+ if (output.errors.length == 0) {
9863
+ output.success = true;
9864
+ }
9865
+ ;
9866
+ return output;
9867
+ }
9740
9868
  /**
9741
9869
  * Build an AJV validator and ensure all valid examples are accepted and all error examples are rejected. Returns an array attribute for each set of examples, plus a general success attribute indicating wether all examples resulted as expected and a failedExamples array only listing entities for which there was no success (meanin unrejected error examples and rejected valid examples).
9742
9870
  */
9743
9871
  testExamples() {
9744
9872
  let generalOutput = {};
9745
9873
  if (!this.validExamples || !this.erroredExamples) {
9746
- throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute`);
9874
+ throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute. Valid examples amount: ${this.validExamples ? this.validExamples.length : "validExamples is not an array"}, errored examples amount: ${this.erroredExamples ? this.erroredExamples.length : "erroredExamples is not an array"}.`);
9747
9875
  }
9748
9876
  ;
9749
9877
  if (this.validExamples.length == 0 || this.erroredExamples.length == 0) {
9750
- throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute`);
9878
+ throw new Error(`Testing can't happen because examples are missing either in the valid or errored attribute. Valid examples amount: ${this.validExamples ? this.validExamples.length : "validExamples is not an array"}, errored examples amount: ${this.erroredExamples ? this.erroredExamples.length : "erroredExamples is not an array"}.`);
9751
9879
  }
9752
9880
  ;
9753
9881
  this.updateSchema();
@@ -9853,7 +9981,7 @@ import TabItem from '@theme/TabItem';
9853
9981
  };
9854
9982
  __name(_ConventionSchema, "ConventionSchema");
9855
9983
  var ConventionSchema2 = _ConventionSchema;
9856
- var _AttributeOverlay = class _AttributeOverlay {
9984
+ var _InputConventionChanges = class _InputConventionChanges {
9857
9985
  constructor({
9858
9986
  type,
9859
9987
  bundle,
@@ -9861,7 +9989,8 @@ import TabItem from '@theme/TabItem';
9861
9989
  baseSchemataFolder = `${__dirname}/../../../../input/collection`,
9862
9990
  sourceSchemataFile = `${__dirname}/../../../../input/farmos.json`,
9863
9991
  overlayName,
9864
- overlayDescription
9992
+ overlayDescription,
9993
+ gitlabProjectId = process.env.CI_PROJECT_ID
9865
9994
  }) {
9866
9995
  let integralSchemataFile = JSON.parse(fs.readFileSync(sourceSchemataFile));
9867
9996
  this.type = type;
@@ -9872,6 +10001,7 @@ import TabItem from '@theme/TabItem';
9872
10001
  this.sourceSchemata = integralSchemataFile;
9873
10002
  this.lexicon = [...findAllObjectAttributesInTree(this.sourceSchemata), ...findAllNonObjectAttributesInTree(this.sourceSchemata)];
9874
10003
  this.baseSchemataFolder = baseSchemataFolder;
10004
+ this.gitlabProjectId = gitlabProjectId;
9875
10005
  let involvedSchemata = this.lexicon.filter((entry) => this.attribute == entry.attribute).flatMap((entry) => entry.instances).filter((instance) => this.type ? instance.type == this.type : true).filter((instance) => this.bundle ? instance.bundle == this.bundle : true).map((d) => d.schema);
9876
10006
  this.targetSchemata = Array.from(new Set(involvedSchemata));
9877
10007
  this.overlays = [];
@@ -9879,8 +10009,10 @@ import TabItem from '@theme/TabItem';
9879
10009
  let currentOverlay = new AttributePatchingSchemaOverlay({
9880
10010
  typeAndBundle: target,
9881
10011
  attributeOverlayName: this.overlayName,
9882
- baseSchemataFolder: this.baseSchemataFolder
10012
+ baseSchemataFolder: this.baseSchemataFolder,
10013
+ gitlabProjectId: this.gitlabProjectId
9883
10014
  });
10015
+ currentOverlay.gitlabProjectId = this.gitlabProjectId;
9884
10016
  this.overlays.push(currentOverlay);
9885
10017
  });
9886
10018
  }
@@ -9941,6 +10073,15 @@ import TabItem from '@theme/TabItem';
9941
10073
  });
9942
10074
  });
9943
10075
  }
10076
+ /**
10077
+ * Mark an attribute to be omitted from the resulting schema.
10078
+ * @param {} attribute
10079
+ */
10080
+ deleteAttribute() {
10081
+ this.overlays.forEach((overlay) => {
10082
+ overlay.deleteAttribute(this.attribute);
10083
+ });
10084
+ }
9944
10085
  /**
9945
10086
  * Stores all involved schemas into the folder structure for `base schemata` (provided as the parameter `baseSchemataFolder`) which will be consumed by our conventions later.
9946
10087
  * @returns {} -- It returns objects containing all paths.
@@ -9953,19 +10094,19 @@ import TabItem from '@theme/TabItem';
9953
10094
  return output;
9954
10095
  }
9955
10096
  };
9956
- __name(_AttributeOverlay, "AttributeOverlay");
9957
- var AttributeOverlay2 = _AttributeOverlay;
10097
+ __name(_InputConventionChanges, "InputConventionChanges");
10098
+ var InputConventionChanges2 = _InputConventionChanges;
9958
10099
  exports2.SchemaOverlay = SchemaOverlay2;
9959
10100
  exports2.ConventionSchema = ConventionSchema2;
9960
- exports2.AttributeOverlay = AttributeOverlay2;
10101
+ exports2.InputConventionChanges = InputConventionChanges2;
9961
10102
  }
9962
10103
  });
9963
10104
 
9964
10105
  // src/index.js
9965
- var { SchemaOverlay, ConventionSchema, AttributeOverlay } = require_convention_builder();
10106
+ var { SchemaOverlay, ConventionSchema, InputConventionChanges } = require_convention_builder();
9966
10107
  var schemaUtils = require_schema_utilities();
9967
10108
  exports.SchemaOverlay = SchemaOverlay;
9968
- exports.AttributeOverlay = AttributeOverlay;
10109
+ exports.InputConventionChanges = InputConventionChanges;
9969
10110
  exports.ConventionSchema = ConventionSchema;
9970
10111
  exports.fixRelationshipDataField = schemaUtils.fixRelationshipDataField;
9971
10112
  exports.buildValidator = schemaUtils.buildValidator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convention_builder",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Helper tools that offer a high level interface that transforms a convention description into it's json schema.",
5
5
  "main": "./dist/node/index.js",
6
6
  "browser": "./dist/browser/index.js",
@@ -42,6 +42,7 @@
42
42
  "jsdoc": "^4.0.2"
43
43
  },
44
44
  "devDependencies": {
45
+ "dotenv": "^16.4.5",
45
46
  "esbuild": "^0.19.7",
46
47
  "jest": "^29.7.0",
47
48
  "jest-junit": "^15.0.0",