@fairfox/polly 0.7.0 → 0.7.2
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/tools/teach/src/cli.js +40 -13
- package/dist/tools/teach/src/cli.js.map +3 -3
- package/dist/tools/teach/src/index.js +40 -13
- package/dist/tools/teach/src/index.js.map +3 -3
- package/dist/tools/verify/src/cli.js +88 -40
- package/dist/tools/verify/src/cli.js.map +4 -4
- package/package.json +2 -2
|
@@ -687,6 +687,17 @@ class TLAGenerator {
|
|
|
687
687
|
return isFirst;
|
|
688
688
|
}
|
|
689
689
|
addStateType(config, _analysis) {
|
|
690
|
+
this.defineValueTypes();
|
|
691
|
+
this.line("\\* Application state type definition");
|
|
692
|
+
this.line("State == [");
|
|
693
|
+
this.indent++;
|
|
694
|
+
const stateFields = this.collectStateFields(config, _analysis);
|
|
695
|
+
this.writeStateFields(stateFields);
|
|
696
|
+
this.indent--;
|
|
697
|
+
this.line("]");
|
|
698
|
+
this.line("");
|
|
699
|
+
}
|
|
700
|
+
defineValueTypes() {
|
|
690
701
|
this.line("\\* Generic value type for sequences and maps");
|
|
691
702
|
this.line("\\* Bounded to allow model checking");
|
|
692
703
|
this.line('Value == {"v1", "v2", "v3"}');
|
|
@@ -695,9 +706,8 @@ class TLAGenerator {
|
|
|
695
706
|
this.line("\\* Bounded to allow model checking");
|
|
696
707
|
this.line('Keys == {"k1", "k2", "k3"}');
|
|
697
708
|
this.line("");
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
this.indent++;
|
|
709
|
+
}
|
|
710
|
+
collectStateFields(config, _analysis) {
|
|
701
711
|
const stateFields = [];
|
|
702
712
|
for (const [fieldPath, fieldConfig] of Object.entries(config.state)) {
|
|
703
713
|
if (typeof fieldConfig !== "object" || fieldConfig === null)
|
|
@@ -707,24 +717,26 @@ class TLAGenerator {
|
|
|
707
717
|
stateFields.push(`${fieldName}: ${tlaType}`);
|
|
708
718
|
}
|
|
709
719
|
for (const fieldAnalysis of _analysis.fields) {
|
|
710
|
-
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
720
|
+
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
711
721
|
continue;
|
|
712
|
-
}
|
|
713
722
|
const fieldName = this.sanitizeFieldName(fieldAnalysis.path);
|
|
714
|
-
if (stateFields.some((f) => f.startsWith(`${fieldName}:`)))
|
|
723
|
+
if (stateFields.some((f) => f.startsWith(`${fieldName}:`)))
|
|
715
724
|
continue;
|
|
716
|
-
}
|
|
717
725
|
const tlaType = this.inferTLATypeFromAnalysis(fieldAnalysis);
|
|
718
726
|
stateFields.push(`${fieldName}: ${tlaType}`);
|
|
719
727
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
728
|
+
return stateFields;
|
|
729
|
+
}
|
|
730
|
+
writeStateFields(fields) {
|
|
731
|
+
if (fields.length === 0) {
|
|
732
|
+
this.line("dummy: BOOLEAN \\* Placeholder for empty state");
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
for (let i = 0;i < fields.length; i++) {
|
|
736
|
+
const field = fields[i];
|
|
737
|
+
const suffix = i < fields.length - 1 ? "," : "";
|
|
723
738
|
this.line(`${field}${suffix}`);
|
|
724
739
|
}
|
|
725
|
-
this.indent--;
|
|
726
|
-
this.line("]");
|
|
727
|
-
this.line("");
|
|
728
740
|
}
|
|
729
741
|
addMessageTypes(_config, analysis) {
|
|
730
742
|
if (analysis.messageTypes.length === 0) {
|
|
@@ -765,6 +777,20 @@ class TLAGenerator {
|
|
|
765
777
|
this.line("\\* Initial application state");
|
|
766
778
|
this.line("InitialState == [");
|
|
767
779
|
this.indent++;
|
|
780
|
+
const fields = this.collectInitialStateFields(config, _analysis);
|
|
781
|
+
this.writeInitialStateFields(fields);
|
|
782
|
+
this.indent--;
|
|
783
|
+
this.line("]");
|
|
784
|
+
this.line("");
|
|
785
|
+
this.line("\\* Initial state (extends MessageRouter)");
|
|
786
|
+
this.line("UserInit ==");
|
|
787
|
+
this.indent++;
|
|
788
|
+
this.line("/\\ Init \\* MessageRouter's init");
|
|
789
|
+
this.line("/\\ contextStates = [c \\in Contexts |-> InitialState]");
|
|
790
|
+
this.indent--;
|
|
791
|
+
this.line("");
|
|
792
|
+
}
|
|
793
|
+
collectInitialStateFields(config, _analysis) {
|
|
768
794
|
const fields = [];
|
|
769
795
|
for (const [fieldPath, fieldConfig] of Object.entries(config.state)) {
|
|
770
796
|
if (typeof fieldConfig !== "object" || fieldConfig === null)
|
|
@@ -774,31 +800,26 @@ class TLAGenerator {
|
|
|
774
800
|
fields.push(`${fieldName} |-> ${initialValue}`);
|
|
775
801
|
}
|
|
776
802
|
for (const fieldAnalysis of _analysis.fields) {
|
|
777
|
-
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
803
|
+
if (!fieldAnalysis.path || typeof fieldAnalysis.path !== "string")
|
|
778
804
|
continue;
|
|
779
|
-
}
|
|
780
805
|
const fieldName = this.sanitizeFieldName(fieldAnalysis.path);
|
|
781
|
-
if (fields.some((f) => f.startsWith(`${fieldName} |->`)))
|
|
806
|
+
if (fields.some((f) => f.startsWith(`${fieldName} |->`)))
|
|
782
807
|
continue;
|
|
783
|
-
}
|
|
784
808
|
const initialValue = this.getInitialValueFromAnalysis(fieldAnalysis);
|
|
785
809
|
fields.push(`${fieldName} |-> ${initialValue}`);
|
|
786
810
|
}
|
|
811
|
+
return fields;
|
|
812
|
+
}
|
|
813
|
+
writeInitialStateFields(fields) {
|
|
814
|
+
if (fields.length === 0) {
|
|
815
|
+
this.line("dummy |-> FALSE \\* Placeholder for empty state");
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
787
818
|
for (let i = 0;i < fields.length; i++) {
|
|
788
819
|
const field = fields[i];
|
|
789
820
|
const suffix = i < fields.length - 1 ? "," : "";
|
|
790
821
|
this.line(`${field}${suffix}`);
|
|
791
822
|
}
|
|
792
|
-
this.indent--;
|
|
793
|
-
this.line("]");
|
|
794
|
-
this.line("");
|
|
795
|
-
this.line("\\* Initial state (extends MessageRouter)");
|
|
796
|
-
this.line("UserInit ==");
|
|
797
|
-
this.indent++;
|
|
798
|
-
this.line("/\\ Init \\* MessageRouter's init");
|
|
799
|
-
this.line("/\\ contextStates = [c \\in Contexts |-> InitialState]");
|
|
800
|
-
this.indent--;
|
|
801
|
-
this.line("");
|
|
802
823
|
}
|
|
803
824
|
addActions(config, analysis) {
|
|
804
825
|
this.line("\\* =============================================================================");
|
|
@@ -3715,11 +3736,24 @@ class TypeExtractor {
|
|
|
3715
3736
|
const stateType = stateFilePath ? this.extractStateType(stateFilePath) : this.findStateType();
|
|
3716
3737
|
const messageTypes = this.findMessageTypes();
|
|
3717
3738
|
const fields = stateType ? this.analyzeFields(stateType) : [];
|
|
3739
|
+
const handlerAnalysis = this.extractHandlerAnalysis();
|
|
3740
|
+
const validMessageTypes = this.filterAndLogMessageTypes(messageTypes, handlerAnalysis.messageTypes);
|
|
3741
|
+
const validHandlers = this.filterAndLogHandlers(handlerAnalysis.handlers);
|
|
3742
|
+
return {
|
|
3743
|
+
stateType,
|
|
3744
|
+
messageTypes: validMessageTypes,
|
|
3745
|
+
fields,
|
|
3746
|
+
handlers: validHandlers
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
extractHandlerAnalysis() {
|
|
3718
3750
|
const configFilePath = this.project.getCompilerOptions()["configFilePath"];
|
|
3719
3751
|
const tsConfigPath = typeof configFilePath === "string" ? configFilePath : "tsconfig.json";
|
|
3720
3752
|
const handlerExtractor = new HandlerExtractor(tsConfigPath);
|
|
3721
|
-
|
|
3722
|
-
|
|
3753
|
+
return handlerExtractor.extractHandlers();
|
|
3754
|
+
}
|
|
3755
|
+
filterAndLogMessageTypes(messageTypes, handlerMessageTypes) {
|
|
3756
|
+
const allMessageTypes = Array.from(new Set([...messageTypes, ...handlerMessageTypes]));
|
|
3723
3757
|
const validMessageTypes = [];
|
|
3724
3758
|
const invalidMessageTypes = [];
|
|
3725
3759
|
for (const msgType of allMessageTypes) {
|
|
@@ -3729,18 +3763,32 @@ class TypeExtractor {
|
|
|
3729
3763
|
invalidMessageTypes.push(msgType);
|
|
3730
3764
|
}
|
|
3731
3765
|
}
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3766
|
+
this.logInvalidMessageTypes(invalidMessageTypes);
|
|
3767
|
+
return validMessageTypes;
|
|
3768
|
+
}
|
|
3769
|
+
logInvalidMessageTypes(invalidMessageTypes) {
|
|
3770
|
+
if (invalidMessageTypes.length === 0 || !process.env["POLLY_DEBUG"])
|
|
3771
|
+
return;
|
|
3772
|
+
console.log(`[WARN] Filtered out ${invalidMessageTypes.length} invalid message type(s):`);
|
|
3773
|
+
for (const invalid of invalidMessageTypes) {
|
|
3774
|
+
console.log(`[WARN] - "${invalid}" (not a valid TLA+ identifier)`);
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
filterAndLogHandlers(handlers) {
|
|
3778
|
+
const validHandlers = handlers.filter((h) => this.isValidTLAIdentifier(h.messageType));
|
|
3779
|
+
this.logInvalidHandlers(handlers, validHandlers);
|
|
3780
|
+
return validHandlers;
|
|
3781
|
+
}
|
|
3782
|
+
logInvalidHandlers(allHandlers, validHandlers) {
|
|
3783
|
+
const filteredHandlerCount = allHandlers.length - validHandlers.length;
|
|
3784
|
+
if (filteredHandlerCount === 0 || !process.env["POLLY_DEBUG"])
|
|
3785
|
+
return;
|
|
3786
|
+
console.log(`[WARN] Filtered out ${filteredHandlerCount} handler(s) with invalid message types:`);
|
|
3787
|
+
for (const handler of allHandlers) {
|
|
3788
|
+
if (!this.isValidTLAIdentifier(handler.messageType)) {
|
|
3789
|
+
console.log(`[WARN] - Handler for "${handler.messageType}" at ${handler.location.file}:${handler.location.line}`);
|
|
3736
3790
|
}
|
|
3737
3791
|
}
|
|
3738
|
-
return {
|
|
3739
|
-
stateType,
|
|
3740
|
-
messageTypes: validMessageTypes,
|
|
3741
|
-
fields,
|
|
3742
|
-
handlers: handlerAnalysis.handlers
|
|
3743
|
-
};
|
|
3744
3792
|
}
|
|
3745
3793
|
isValidTLAIdentifier(s) {
|
|
3746
3794
|
if (!s || s.length === 0) {
|
|
@@ -4499,4 +4547,4 @@ main().catch((error) => {
|
|
|
4499
4547
|
process.exit(1);
|
|
4500
4548
|
});
|
|
4501
4549
|
|
|
4502
|
-
//# debugId=
|
|
4550
|
+
//# debugId=6EFAE591D90C88BD64756E2164756E21
|