@rljson/rljson 0.0.15 → 0.0.16
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.
- package/dist/index.d.ts +4 -0
- package/dist/rljson.js +664 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,11 @@ export * from './content/cake.ts';
|
|
|
3
3
|
export * from './content/collection.ts';
|
|
4
4
|
export * from './content/id-set.ts';
|
|
5
5
|
export * from './content/properties.ts';
|
|
6
|
+
export * from './content/table-cfg.ts';
|
|
6
7
|
export * from './example.ts';
|
|
8
|
+
export * from './example/bakery-example.ts';
|
|
7
9
|
export * from './rljson-indexed.ts';
|
|
8
10
|
export * from './rljson.ts';
|
|
9
11
|
export * from './typedefs.ts';
|
|
12
|
+
export * from './validate/base-validator.ts';
|
|
13
|
+
export * from './validate/validate.ts';
|
package/dist/rljson.js
CHANGED
|
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { hip, hsh } from "@rljson/hash";
|
|
5
|
-
import { exampleJsonObject } from "@rljson/json";
|
|
5
|
+
import { exampleJsonObject, jsonValueTypes, jsonValueMatchesType } from "@rljson/json";
|
|
6
6
|
// @license
|
|
7
7
|
const bakeryExample = () => {
|
|
8
8
|
const result = {
|
|
@@ -483,6 +483,8 @@ __publicField(_Example, "broken", {
|
|
|
483
483
|
});
|
|
484
484
|
let Example = _Example;
|
|
485
485
|
// @license
|
|
486
|
+
const exampleTableCfgTable = () => Example.ok.singleRow()._tableCfgs;
|
|
487
|
+
// @license
|
|
486
488
|
const rljsonIndexed = (rljson) => {
|
|
487
489
|
const result = {};
|
|
488
490
|
for (const key in rljson) {
|
|
@@ -527,15 +529,676 @@ const exampleTypedefs = () => {
|
|
|
527
529
|
contentType: "collections"
|
|
528
530
|
};
|
|
529
531
|
};
|
|
532
|
+
// @license
|
|
533
|
+
class BaseValidator {
|
|
534
|
+
constructor() {
|
|
535
|
+
__publicField(this, "name", "syntax");
|
|
536
|
+
}
|
|
537
|
+
async validate(rljson) {
|
|
538
|
+
return this.validateSync(rljson);
|
|
539
|
+
}
|
|
540
|
+
validateSync(rljson) {
|
|
541
|
+
return new _BaseValidator(rljson).validate();
|
|
542
|
+
}
|
|
543
|
+
static isValidFieldName(fieldName) {
|
|
544
|
+
return /^[a-z][a-zA-Z0-9]*$/.test(fieldName);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
class _BaseValidator {
|
|
548
|
+
constructor(rljson) {
|
|
549
|
+
__publicField(this, "errors", { hasErrors: false });
|
|
550
|
+
// ######################
|
|
551
|
+
// Private
|
|
552
|
+
// ######################
|
|
553
|
+
__publicField(this, "tableNames");
|
|
554
|
+
__publicField(this, "rljsonIndexed");
|
|
555
|
+
this.rljson = rljson;
|
|
556
|
+
this.tableNames = Object.keys(this.rljson).filter(
|
|
557
|
+
(table) => !table.startsWith("_")
|
|
558
|
+
);
|
|
559
|
+
this.rljsonIndexed = rljsonIndexed(rljson);
|
|
560
|
+
}
|
|
561
|
+
get hasErrors() {
|
|
562
|
+
return Object.keys(this.errors).length > 1;
|
|
563
|
+
}
|
|
564
|
+
validate() {
|
|
565
|
+
const steps = [
|
|
566
|
+
// Base checks
|
|
567
|
+
() => this._writeAndValidHashes(),
|
|
568
|
+
() => this._tableNamesNotLowerCamelCase(),
|
|
569
|
+
() => this._tableNamesDoNotEndWithRef(),
|
|
570
|
+
() => this._columnNamesNotLowerCamelCase(),
|
|
571
|
+
() => this._dataNotFound(),
|
|
572
|
+
() => this._dataHasWrongType(),
|
|
573
|
+
// Check table cfg
|
|
574
|
+
() => this._tableCfgsReferencedTableNameNotFound(),
|
|
575
|
+
() => this._tableCfgsHaveWrongType(),
|
|
576
|
+
() => this._tableCfgNotFound(),
|
|
577
|
+
() => this._missingColumnConfigs(),
|
|
578
|
+
() => this._dataDoesNotMatchColumnConfig(),
|
|
579
|
+
// Check references
|
|
580
|
+
() => this._refsNotFound(),
|
|
581
|
+
// Check collections
|
|
582
|
+
() => this._collectionBasesNotFound(),
|
|
583
|
+
() => this._collectionIdSetsExist(),
|
|
584
|
+
() => this._collectionPropertyAssignmentsNotFound(),
|
|
585
|
+
// Check cakes
|
|
586
|
+
() => this._cakeIdSetsNotFound(),
|
|
587
|
+
() => this._cakeCollectionTablesNotFound(),
|
|
588
|
+
// Check buffets
|
|
589
|
+
() => this._buffetReferencedTableNotFound()
|
|
590
|
+
];
|
|
591
|
+
for (const step of steps) {
|
|
592
|
+
step();
|
|
593
|
+
if (this.hasErrors) {
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
this.errors.hasErrors = this.hasErrors;
|
|
598
|
+
return this.errors;
|
|
599
|
+
}
|
|
600
|
+
_tableNamesNotLowerCamelCase() {
|
|
601
|
+
const invalidTableNames = [];
|
|
602
|
+
for (const tableName of this.tableNames) {
|
|
603
|
+
if (!BaseValidator.isValidFieldName(tableName)) {
|
|
604
|
+
invalidTableNames.push(tableName);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (invalidTableNames.length > 0) {
|
|
608
|
+
this.errors.tableNamesNotLowerCamelCase = {
|
|
609
|
+
error: "Table names must be lower camel case",
|
|
610
|
+
invalidTableNames
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// ...........................................................................
|
|
615
|
+
_tableNamesDoNotEndWithRef() {
|
|
616
|
+
const invalidTableNames = [];
|
|
617
|
+
for (const tableName of this.tableNames) {
|
|
618
|
+
if (tableName.endsWith("Ref")) {
|
|
619
|
+
invalidTableNames.push(tableName);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (invalidTableNames.length > 0) {
|
|
623
|
+
this.errors.tableNamesDoNotEndWithRef = {
|
|
624
|
+
error: 'Table names must not end with "Ref"',
|
|
625
|
+
invalidTableNames
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
// ...........................................................................
|
|
630
|
+
_columnNamesNotLowerCamelCase() {
|
|
631
|
+
const invalidColumnNames = {};
|
|
632
|
+
let hadErrors = false;
|
|
633
|
+
for (const tableName of this.tableNames) {
|
|
634
|
+
const table = this.rljson[tableName];
|
|
635
|
+
if (!table._data || !Array.isArray(table._data)) {
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
for (const row of table._data) {
|
|
639
|
+
for (const columnName in row) {
|
|
640
|
+
if (columnName.startsWith("_")) {
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (!BaseValidator.isValidFieldName(columnName)) {
|
|
644
|
+
invalidColumnNames[tableName] ?? (invalidColumnNames[tableName] = []);
|
|
645
|
+
invalidColumnNames[tableName].push(columnName);
|
|
646
|
+
hadErrors = true;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (hadErrors) {
|
|
652
|
+
this.errors.columnNamesNotLowerCamelCase = {
|
|
653
|
+
error: "Column names must be lower camel case",
|
|
654
|
+
invalidColumnNames
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
// ...........................................................................
|
|
659
|
+
_writeAndValidHashes() {
|
|
660
|
+
try {
|
|
661
|
+
this.rljson = hsh(this.rljson, {
|
|
662
|
+
inPlace: false,
|
|
663
|
+
updateExistingHashes: true,
|
|
664
|
+
throwOnWrongHashes: true
|
|
665
|
+
});
|
|
666
|
+
} catch (error) {
|
|
667
|
+
if (error instanceof Error) {
|
|
668
|
+
this.errors.hashesNotValid = {
|
|
669
|
+
error: error.message
|
|
670
|
+
};
|
|
671
|
+
} else {
|
|
672
|
+
this.errors.hashesNotValid = {
|
|
673
|
+
error: "Unknown error"
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
// ...........................................................................
|
|
679
|
+
/// Checks if data is valid
|
|
680
|
+
_dataNotFound() {
|
|
681
|
+
const rljson = this.rljson;
|
|
682
|
+
const tablesWithMissingData = [];
|
|
683
|
+
for (const table of this.tableNames) {
|
|
684
|
+
const tableData = rljson[table];
|
|
685
|
+
const items = tableData["_data"];
|
|
686
|
+
if (items == null) {
|
|
687
|
+
tablesWithMissingData.push(table);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (tablesWithMissingData.length > 0) {
|
|
691
|
+
this.errors.dataNotFound = {
|
|
692
|
+
error: "_data is missing in tables",
|
|
693
|
+
tables: tablesWithMissingData
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
// ...........................................................................
|
|
698
|
+
_tableCfgsReferencedTableNameNotFound() {
|
|
699
|
+
const tableCfgs = this.rljson._tableCfgs;
|
|
700
|
+
if (!tableCfgs) {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
const brokenCfgs = [];
|
|
704
|
+
for (const item of tableCfgs._data) {
|
|
705
|
+
const table = this.rljson[item.jsonKey];
|
|
706
|
+
if (!table) {
|
|
707
|
+
brokenCfgs.push({
|
|
708
|
+
brokenTableCfg: item._hash,
|
|
709
|
+
tableNameNotFound: item.jsonKey
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (brokenCfgs.length > 0) {
|
|
714
|
+
this.errors.tableCfgsReferencedTableNameNotFound = {
|
|
715
|
+
error: "Tables referenced in _tableCfgs not found",
|
|
716
|
+
brokenCfgs
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
// ...........................................................................
|
|
721
|
+
_tableCfgsHaveWrongType() {
|
|
722
|
+
const tableCfgs = this.rljson._tableCfgs;
|
|
723
|
+
if (!tableCfgs) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
const brokenCfgs = [];
|
|
727
|
+
for (const item of tableCfgs._data) {
|
|
728
|
+
for (const columnKey in item.columns) {
|
|
729
|
+
if (columnKey.startsWith("_")) {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
const column = item.columns[columnKey];
|
|
733
|
+
if (jsonValueTypes.indexOf(column.type) === -1) {
|
|
734
|
+
brokenCfgs.push({
|
|
735
|
+
brokenTableCfg: item._hash,
|
|
736
|
+
brokenColumnKey: columnKey,
|
|
737
|
+
brokenColumnType: column.type
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (brokenCfgs.length > 0) {
|
|
743
|
+
this.errors.tableCfgsHaveWrongTypes = {
|
|
744
|
+
error: "Some of the columns have invalid types. Valid types are: " + jsonValueTypes.join(", "),
|
|
745
|
+
brokenCfgs
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
// ...........................................................................
|
|
750
|
+
_tableCfgNotFound() {
|
|
751
|
+
const tableCfgs = this.rljsonIndexed._tableCfgs;
|
|
752
|
+
const tableCfgNotFound = [];
|
|
753
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
754
|
+
const tableCfgRef = table._tableCfg;
|
|
755
|
+
if (!tableCfgRef) {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
const tableCfgData = tableCfgs._data[tableCfgRef];
|
|
759
|
+
if (!tableCfgData) {
|
|
760
|
+
tableCfgNotFound.push({
|
|
761
|
+
tableWithBrokenTableCfgRef: tableName,
|
|
762
|
+
brokenTableCfgRef: tableCfgRef
|
|
763
|
+
});
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
if (tableCfgNotFound.length > 0) {
|
|
768
|
+
this.errors.tableCfgReferencedNotFound = {
|
|
769
|
+
error: "Referenced table config not found",
|
|
770
|
+
tableCfgNotFound
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
// ...........................................................................
|
|
775
|
+
_missingColumnConfigs() {
|
|
776
|
+
const tableCfgs = this.rljsonIndexed._tableCfgs;
|
|
777
|
+
const missingColumnConfigs = [];
|
|
778
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
779
|
+
const tableCfgRef = table._tableCfg;
|
|
780
|
+
if (!tableCfgRef) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
const tableCfgData = tableCfgs._data[tableCfgRef];
|
|
784
|
+
const processedColumnKeys = [];
|
|
785
|
+
for (const row of table._data) {
|
|
786
|
+
const columnKeys = Object.keys(row).filter(
|
|
787
|
+
(key) => !key.startsWith("_")
|
|
788
|
+
);
|
|
789
|
+
const newColumnKey = columnKeys.filter(
|
|
790
|
+
(key) => processedColumnKeys.indexOf(key) === -1
|
|
791
|
+
);
|
|
792
|
+
for (const columnKey of newColumnKey) {
|
|
793
|
+
if (!tableCfgData.columns[columnKey]) {
|
|
794
|
+
missingColumnConfigs.push({
|
|
795
|
+
tableCfg: tableCfgRef,
|
|
796
|
+
row: row._hash,
|
|
797
|
+
column: columnKey,
|
|
798
|
+
table: tableName
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
processedColumnKeys.push(columnKey);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
if (missingColumnConfigs.length > 0) {
|
|
806
|
+
this.errors.columnConfigNotFound = {
|
|
807
|
+
error: "Column configurations not found",
|
|
808
|
+
missingColumnConfigs
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// ...........................................................................
|
|
813
|
+
_dataDoesNotMatchColumnConfig() {
|
|
814
|
+
const tableCfgs = this.rljsonIndexed._tableCfgs;
|
|
815
|
+
const brokenValues = [];
|
|
816
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
817
|
+
const tableCfgRef = table._tableCfg;
|
|
818
|
+
if (!tableCfgRef) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const tableCfgData = tableCfgs._data[tableCfgRef];
|
|
822
|
+
for (const row of table._data) {
|
|
823
|
+
const columnKeys = Object.keys(row).filter(
|
|
824
|
+
(key) => !key.startsWith("_")
|
|
825
|
+
);
|
|
826
|
+
for (const columnKey of columnKeys) {
|
|
827
|
+
const columnConfig = tableCfgData.columns[columnKey];
|
|
828
|
+
const value = row[columnKey];
|
|
829
|
+
if (value == null || value == void 0) {
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
const typeShould = columnConfig.type;
|
|
833
|
+
if (!jsonValueMatchesType(value, typeShould)) {
|
|
834
|
+
brokenValues.push({
|
|
835
|
+
table: tableName,
|
|
836
|
+
row: row._hash,
|
|
837
|
+
column: columnKey,
|
|
838
|
+
tableCfg: tableCfgRef
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
if (brokenValues.length > 0) {
|
|
845
|
+
this.errors.dataDoesNotMatchColumnConfig = {
|
|
846
|
+
error: "Table values have wrong types",
|
|
847
|
+
brokenValues
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// ...........................................................................
|
|
852
|
+
_dataHasWrongType() {
|
|
853
|
+
const rljson = this.rljson;
|
|
854
|
+
const tablesWithWrongType = [];
|
|
855
|
+
for (const tableName of this.tableNames) {
|
|
856
|
+
const tableData = rljson[tableName];
|
|
857
|
+
const items = tableData["_data"];
|
|
858
|
+
if (!Array.isArray(items)) {
|
|
859
|
+
tablesWithWrongType.push(tableName);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
if (tablesWithWrongType.length > 0) {
|
|
863
|
+
this.errors.dataHasWrongType = {
|
|
864
|
+
error: "_data must be a list",
|
|
865
|
+
tables: tablesWithWrongType
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
_refsNotFound() {
|
|
870
|
+
const missingRefs = [];
|
|
871
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
872
|
+
const tableData = table._data;
|
|
873
|
+
for (const item of tableData) {
|
|
874
|
+
for (const key of Object.keys(item)) {
|
|
875
|
+
if (key.endsWith("Ref")) {
|
|
876
|
+
const targetItemHash = item[key];
|
|
877
|
+
const targetTableName = key.substring(0, key.length - 3);
|
|
878
|
+
const itemHash = item._hash;
|
|
879
|
+
if (this.tableNames.indexOf(targetTableName) === -1) {
|
|
880
|
+
missingRefs.push({
|
|
881
|
+
error: `Target table "${targetTableName}" not found.`,
|
|
882
|
+
sourceTable: tableName,
|
|
883
|
+
sourceKey: key,
|
|
884
|
+
sourceItemHash: itemHash,
|
|
885
|
+
targetItemHash,
|
|
886
|
+
targetTable: targetTableName
|
|
887
|
+
});
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
const targetTableIndexed = this.rljsonIndexed[targetTableName];
|
|
891
|
+
const referencedItem = targetTableIndexed._data[targetItemHash];
|
|
892
|
+
if (referencedItem === void 0) {
|
|
893
|
+
missingRefs.push({
|
|
894
|
+
sourceTable: tableName,
|
|
895
|
+
sourceItemHash: itemHash,
|
|
896
|
+
sourceKey: key,
|
|
897
|
+
targetItemHash,
|
|
898
|
+
targetTable: targetTableName,
|
|
899
|
+
error: `Table "${targetTableName}" has no item with hash "${targetItemHash}"`
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
if (missingRefs.length > 0) {
|
|
907
|
+
this.errors.refsNotFound = {
|
|
908
|
+
error: "Broken references",
|
|
909
|
+
missingRefs
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
_collectionBasesNotFound() {
|
|
914
|
+
const brokenCollections = [];
|
|
915
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
916
|
+
if (table._type !== "collections") {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const collectionsIndexed = this.rljsonIndexed[tableName];
|
|
920
|
+
const collectionsTable = table;
|
|
921
|
+
for (const collection of collectionsTable._data) {
|
|
922
|
+
const baseRef = collection.base;
|
|
923
|
+
if (!baseRef) {
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
const baseCollection = collectionsIndexed._data[baseRef];
|
|
927
|
+
if (!baseCollection) {
|
|
928
|
+
brokenCollections.push({
|
|
929
|
+
collectionsTable: tableName,
|
|
930
|
+
brokenCollection: collection._hash,
|
|
931
|
+
missingBaseCollection: baseRef
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
if (brokenCollections.length > 0) {
|
|
937
|
+
this.errors.collectionBasesNotFound = {
|
|
938
|
+
error: "Base collections are missing",
|
|
939
|
+
brokenCollections
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
_collectionIdSetsExist() {
|
|
944
|
+
const brokenCollections = [];
|
|
945
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
946
|
+
if (table._type !== "collections") {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const idSets = this.rljsonIndexed._idSets;
|
|
950
|
+
const collectionsTable = table;
|
|
951
|
+
for (const collection of collectionsTable._data) {
|
|
952
|
+
const idSetRef = collection.idSet;
|
|
953
|
+
if (!idSetRef) {
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
const idSet = idSets._data[idSetRef];
|
|
957
|
+
if (!idSet) {
|
|
958
|
+
brokenCollections.push({
|
|
959
|
+
collectionsTable: tableName,
|
|
960
|
+
collectionHash: collection._hash,
|
|
961
|
+
missingIdSet: idSetRef
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
if (brokenCollections.length > 0) {
|
|
967
|
+
this.errors.collectionIdSetsExist = {
|
|
968
|
+
error: "Id sets of collections are missing",
|
|
969
|
+
brokenCollections
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
_collectionPropertyAssignmentsNotFound() {
|
|
974
|
+
const missingPropertyTables = [];
|
|
975
|
+
const brokenAssignments = [];
|
|
976
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
977
|
+
if (table._type !== "collections") {
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const collectionsTable = table;
|
|
981
|
+
for (const collection of collectionsTable._data) {
|
|
982
|
+
const propertyTableName = collection.properties;
|
|
983
|
+
const propertiesTable = this.rljsonIndexed[propertyTableName];
|
|
984
|
+
if (!propertiesTable) {
|
|
985
|
+
missingPropertyTables.push({
|
|
986
|
+
brokenCollection: collection._hash,
|
|
987
|
+
collectionsTable: tableName,
|
|
988
|
+
missingPropertyTable: propertyTableName
|
|
989
|
+
});
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
const assignments = collection.assign;
|
|
993
|
+
for (const itemId in assignments) {
|
|
994
|
+
if (itemId.startsWith("_")) {
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
const propertyHash = assignments[itemId];
|
|
998
|
+
if (!propertiesTable._data[propertyHash]) {
|
|
999
|
+
brokenAssignments.push({
|
|
1000
|
+
collectionsTable: tableName,
|
|
1001
|
+
brokenCollection: collection._hash,
|
|
1002
|
+
referencedPropertyTable: propertyTableName,
|
|
1003
|
+
brokenAssignment: itemId,
|
|
1004
|
+
missingProperty: propertyHash
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
if (missingPropertyTables.length > 0) {
|
|
1011
|
+
this.errors.collectionPropertyTablesNotFound = {
|
|
1012
|
+
error: "Collection property tables do not exist",
|
|
1013
|
+
collections: missingPropertyTables
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
if (brokenAssignments.length > 0) {
|
|
1017
|
+
this.errors.collectionPropertyAssignmentsNotFound = {
|
|
1018
|
+
error: "Collection property assignments are broken",
|
|
1019
|
+
brokenAssignments
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
_cakeIdSetsNotFound() {
|
|
1024
|
+
const brokenCakes = [];
|
|
1025
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
1026
|
+
if (table._type !== "cakes") {
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
const idSets = this.rljsonIndexed._idSets;
|
|
1030
|
+
const cakesTable = table;
|
|
1031
|
+
for (const cake of cakesTable._data) {
|
|
1032
|
+
const idSetRef = cake.idSet;
|
|
1033
|
+
if (!idSetRef) {
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
const idSet = idSets._data[idSetRef];
|
|
1037
|
+
if (!idSet) {
|
|
1038
|
+
brokenCakes.push({
|
|
1039
|
+
cakeTable: tableName,
|
|
1040
|
+
brokenCake: cake._hash,
|
|
1041
|
+
missingIdSet: idSetRef
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
if (brokenCakes.length > 0) {
|
|
1047
|
+
this.errors.cakeIdSetsNotFound = {
|
|
1048
|
+
error: "Id sets of cakes are missing",
|
|
1049
|
+
brokenCakes
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
_cakeCollectionTablesNotFound() {
|
|
1054
|
+
const missingCollectionTables = [];
|
|
1055
|
+
const missingLayerCollections = [];
|
|
1056
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
1057
|
+
if (table._type !== "cakes") {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const cakesTable = table;
|
|
1061
|
+
for (const cake of cakesTable._data) {
|
|
1062
|
+
const collectionsTableName = cake.collections;
|
|
1063
|
+
const collectionsTable = this.rljsonIndexed[collectionsTableName];
|
|
1064
|
+
if (!collectionsTable) {
|
|
1065
|
+
missingCollectionTables.push({
|
|
1066
|
+
cakeTable: tableName,
|
|
1067
|
+
brokenCake: cake._hash,
|
|
1068
|
+
missingCollectionsTable: collectionsTableName
|
|
1069
|
+
});
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
for (const layer in cake.layers) {
|
|
1073
|
+
if (layer.startsWith("_")) {
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
const collectionRef = cake.layers[layer];
|
|
1077
|
+
const collection = collectionsTable._data[collectionRef];
|
|
1078
|
+
if (!collection) {
|
|
1079
|
+
missingLayerCollections.push({
|
|
1080
|
+
cakeTable: tableName,
|
|
1081
|
+
brokenCake: cake._hash,
|
|
1082
|
+
brokenLayerName: layer,
|
|
1083
|
+
collectionsTable: collectionsTableName,
|
|
1084
|
+
missingCollection: collectionRef
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
if (missingCollectionTables.length > 0) {
|
|
1091
|
+
this.errors.cakeCollectionTablesNotFound = {
|
|
1092
|
+
error: "Collection tables of cakes are missing",
|
|
1093
|
+
brokenCakes: missingCollectionTables
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
if (missingLayerCollections.length > 0) {
|
|
1097
|
+
this.errors.cakeLayerCollectionsNotFound = {
|
|
1098
|
+
error: "Layer collections of cakes are missing",
|
|
1099
|
+
brokenCakes: missingLayerCollections
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
_buffetReferencedTableNotFound() {
|
|
1104
|
+
const missingTables = [];
|
|
1105
|
+
const missingItems = [];
|
|
1106
|
+
iterateTables(this.rljson, (tableName, table) => {
|
|
1107
|
+
if (table._type !== "buffets") {
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
const buffetsTable = table;
|
|
1111
|
+
for (const buffet of buffetsTable._data) {
|
|
1112
|
+
for (const item of buffet.items) {
|
|
1113
|
+
const itemTableName = item.table;
|
|
1114
|
+
const itemTable = this.rljsonIndexed[itemTableName];
|
|
1115
|
+
if (!itemTable) {
|
|
1116
|
+
missingTables.push({
|
|
1117
|
+
buffetTable: tableName,
|
|
1118
|
+
brokenBuffet: buffet._hash,
|
|
1119
|
+
missingItemTable: itemTableName
|
|
1120
|
+
});
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
const ref = item.ref;
|
|
1124
|
+
const referencedItem = itemTable._data[ref];
|
|
1125
|
+
if (!referencedItem) {
|
|
1126
|
+
missingItems.push({
|
|
1127
|
+
buffetTable: tableName,
|
|
1128
|
+
brokenBuffet: buffet._hash,
|
|
1129
|
+
itemTable: itemTableName,
|
|
1130
|
+
missingItem: ref
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
if (missingTables.length > 0) {
|
|
1137
|
+
this.errors.buffetReferencedTablesNotFound = {
|
|
1138
|
+
error: "Referenced tables of buffets are missing",
|
|
1139
|
+
brokenBuffets: missingTables
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
if (missingItems.length > 0) {
|
|
1143
|
+
this.errors.buffetReferencedItemsNotFound = {
|
|
1144
|
+
error: "Referenced items of buffets are missing",
|
|
1145
|
+
brokenItems: missingItems
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
const isValidFieldName = (fieldName) => BaseValidator.isValidFieldName(fieldName);
|
|
1151
|
+
// @license
|
|
1152
|
+
class Validate {
|
|
1153
|
+
constructor() {
|
|
1154
|
+
// ######################
|
|
1155
|
+
// Private
|
|
1156
|
+
// ######################
|
|
1157
|
+
__publicField(this, "_validators", []);
|
|
1158
|
+
}
|
|
1159
|
+
addValidator(validator) {
|
|
1160
|
+
this._validators.push(validator);
|
|
1161
|
+
}
|
|
1162
|
+
async run(rljson) {
|
|
1163
|
+
const result = await Promise.all(
|
|
1164
|
+
this._validators.map(async (validator) => {
|
|
1165
|
+
const errors = await validator.validate(rljson);
|
|
1166
|
+
const name = validator.name;
|
|
1167
|
+
return {
|
|
1168
|
+
[name]: errors
|
|
1169
|
+
};
|
|
1170
|
+
})
|
|
1171
|
+
);
|
|
1172
|
+
return result.reduce((acc, errors) => {
|
|
1173
|
+
let hasErrors = false;
|
|
1174
|
+
for (const key of Object.keys(errors)) {
|
|
1175
|
+
const e = Object.keys(errors[key]);
|
|
1176
|
+
if (e.length > 0) {
|
|
1177
|
+
hasErrors = true;
|
|
1178
|
+
break;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
if (hasErrors) {
|
|
1182
|
+
return { ...acc, ...errors };
|
|
1183
|
+
}
|
|
1184
|
+
return acc;
|
|
1185
|
+
}, {});
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
530
1188
|
export {
|
|
1189
|
+
BaseValidator,
|
|
531
1190
|
Example,
|
|
1191
|
+
Validate,
|
|
1192
|
+
bakeryExample,
|
|
532
1193
|
exampleBuffetsTable,
|
|
533
1194
|
exampleCakesTable,
|
|
534
1195
|
exampleCollectionsTable,
|
|
535
1196
|
exampleIdSetsTable,
|
|
536
1197
|
examplePropertiesTable,
|
|
537
1198
|
exampleRljson,
|
|
1199
|
+
exampleTableCfgTable,
|
|
538
1200
|
exampleTypedefs,
|
|
1201
|
+
isValidFieldName,
|
|
539
1202
|
iterateTables,
|
|
540
1203
|
reservedFieldNames,
|
|
541
1204
|
reservedTableNames,
|