@dusted/anqst 0.1.1 → 0.1.3
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/README.md +99 -117
- package/dist/src/app.js +180 -272
- package/dist/src/build-stamp.js +5 -0
- package/dist/src/{backend/tsc/debug-dump.js → debug-dump.js} +2 -1
- package/dist/src/emit.js +368 -170
- package/dist/src/layout.js +70 -0
- package/dist/src/parser.js +124 -6
- package/dist/src/{backend/tsc/program.js → program.js} +1 -1
- package/dist/src/project.js +220 -137
- package/dist/src/verify.js +15 -2
- package/index.d.ts +1 -0
- package/package.json +7 -2
- package/spec/AnQst-Spec-DSL.d.ts +49 -17
- package/dist/src/backend/ast/emit.js +0 -5
- package/dist/src/backend/ast/index.js +0 -13
- package/dist/src/backend/ast/parser.js +0 -5
- package/dist/src/backend/ast/verify.js +0 -5
- package/dist/src/backend/index.js +0 -16
- package/dist/src/backend/tsc/emit-cpp.js +0 -13
- package/dist/src/backend/tsc/emit-node.js +0 -13
- package/dist/src/backend/tsc/index.js +0 -41
- package/dist/src/backend/tsc/parser.js +0 -19
- package/dist/src/backend/tsc/verify.js +0 -13
- package/dist/src/backend/types.js +0 -2
- /package/dist/src/{backend/tsc/typegraph.js → typegraph.js} +0 -0
package/dist/src/emit.js
CHANGED
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateOutputs = generateOutputs;
|
|
7
7
|
exports.writeGeneratedOutputs = writeGeneratedOutputs;
|
|
8
|
-
exports.installTypeScriptOutputs = installTypeScriptOutputs;
|
|
9
8
|
exports.installEmbeddedWebBundle = installEmbeddedWebBundle;
|
|
10
9
|
exports.installQtIntegrationCMake = installQtIntegrationCMake;
|
|
11
10
|
exports.installQtDesignerPluginCMake = installQtDesignerPluginCMake;
|
|
@@ -13,6 +12,8 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
13
12
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
13
|
const typescript_1 = __importDefault(require("typescript"));
|
|
15
14
|
const pngjs_1 = require("pngjs");
|
|
15
|
+
const build_stamp_1 = require("./build-stamp");
|
|
16
|
+
const layout_1 = require("./layout");
|
|
16
17
|
function stripAnQstType(typeText) {
|
|
17
18
|
return typeText
|
|
18
19
|
.replace(/\bAnQst\.Type\.stringArray\b/g, "string[]")
|
|
@@ -349,7 +350,7 @@ function normalizeImportPathForGenerated(specFilePath, generatedFileRelPath, mod
|
|
|
349
350
|
return moduleSpecifier;
|
|
350
351
|
}
|
|
351
352
|
const specDir = node_path_1.default.dirname(specFilePath);
|
|
352
|
-
const generatedAbs = node_path_1.default.resolve(node_path_1.default.dirname(specFilePath), "
|
|
353
|
+
const generatedAbs = node_path_1.default.resolve(node_path_1.default.dirname(specFilePath), "generated", generatedFileRelPath);
|
|
353
354
|
const generatedDir = node_path_1.default.dirname(generatedAbs);
|
|
354
355
|
const resolvedModulePath = node_path_1.default.resolve(specDir, moduleSpecifier);
|
|
355
356
|
const relative = node_path_1.default.relative(generatedDir, resolvedModulePath);
|
|
@@ -652,13 +653,24 @@ ${decls}
|
|
|
652
653
|
${metatypes}
|
|
653
654
|
`;
|
|
654
655
|
}
|
|
656
|
+
function renderWidgetUmbrellaHeader(spec) {
|
|
657
|
+
return `#pragma once
|
|
658
|
+
// Built by <AnQst_version>
|
|
659
|
+
#include "${spec.widgetName}Widget.h"
|
|
660
|
+
#include "${spec.widgetName}Types.h"
|
|
661
|
+
`;
|
|
662
|
+
}
|
|
655
663
|
function renderWidgetHeader(spec, cppTypes) {
|
|
664
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
656
665
|
const callbackAliases = [];
|
|
657
666
|
const publicMethods = [];
|
|
667
|
+
const slotMethods = [];
|
|
668
|
+
const handleMethods = [];
|
|
669
|
+
const callSetterMethods = [];
|
|
658
670
|
const signals = [];
|
|
659
671
|
const properties = [];
|
|
660
672
|
const fields = [];
|
|
661
|
-
const
|
|
673
|
+
const publicSlots = [];
|
|
662
674
|
const bindings = [];
|
|
663
675
|
for (const service of spec.services) {
|
|
664
676
|
for (const member of service.members) {
|
|
@@ -666,21 +678,20 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
666
678
|
const memberPascal = pascalCase(member.name);
|
|
667
679
|
if (member.kind === "Call" && member.payloadTypeText) {
|
|
668
680
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
669
|
-
const args = member.parameters.map((p) =>
|
|
681
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
670
682
|
callbackAliases.push(`using ${memberPascal}Handler = std::function<${cppType}(${args})>;`);
|
|
671
|
-
|
|
683
|
+
handleMethods.push(` void ${member.name}(const ${memberPascal}Handler& handler) const;`);
|
|
684
|
+
callSetterMethods.push(`void set${memberPascal}CallHandler(const ${memberPascal}Handler& handler);`);
|
|
672
685
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
673
686
|
}
|
|
674
687
|
else if (member.kind === "Emitter") {
|
|
675
|
-
const args = member.parameters.map((p) =>
|
|
676
|
-
|
|
677
|
-
publicMethods.push(`void set${memberPascal}Handler(const ${memberPascal}Handler& handler);`);
|
|
678
|
-
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
688
|
+
const args = member.parameters.map((p) => `const ${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])}& ${p.name}`).join(", ");
|
|
689
|
+
signals.push(`void ${member.name}(${args});`);
|
|
679
690
|
}
|
|
680
691
|
else if (member.kind === "Slot") {
|
|
681
692
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
682
693
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
683
|
-
|
|
694
|
+
slotMethods.push(`${ret} slot_${member.name}(${args});`);
|
|
684
695
|
}
|
|
685
696
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
686
697
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
@@ -696,13 +707,16 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
696
707
|
fields.push(`${memberPascal}Handler m_${member.name}Handler;`);
|
|
697
708
|
}
|
|
698
709
|
else {
|
|
699
|
-
|
|
710
|
+
publicSlots.push(`void ${member.name}Slot(const ${cppType}& value);`);
|
|
700
711
|
}
|
|
701
712
|
}
|
|
702
713
|
}
|
|
703
714
|
}
|
|
704
715
|
return `#pragma once
|
|
716
|
+
#include <QDateTime>
|
|
705
717
|
#include <QHash>
|
|
718
|
+
#include <QMetaMethod>
|
|
719
|
+
#include <QQueue>
|
|
706
720
|
#include <QVariant>
|
|
707
721
|
#include <QVariantList>
|
|
708
722
|
#include <functional>
|
|
@@ -710,28 +724,54 @@ function renderWidgetHeader(spec, cppTypes) {
|
|
|
710
724
|
#include "${spec.widgetName}Types.h"
|
|
711
725
|
|
|
712
726
|
namespace ${spec.widgetName} {
|
|
727
|
+
} // namespace ${spec.widgetName}
|
|
728
|
+
|
|
729
|
+
using namespace ${spec.widgetName};
|
|
713
730
|
|
|
714
|
-
class ${
|
|
731
|
+
class ${widgetClassName} : public AnQstWebHostBase {
|
|
715
732
|
Q_OBJECT
|
|
716
733
|
${properties.map((p) => ` ${p}`).join("\n")}
|
|
717
734
|
|
|
718
735
|
public:
|
|
719
|
-
|
|
720
|
-
|
|
736
|
+
${callbackAliases.map((s) => ` ${s}`).join("\n")}
|
|
737
|
+
|
|
738
|
+
class handle {
|
|
739
|
+
public:
|
|
740
|
+
explicit handle(${widgetClassName}* owner) : m_owner(owner) {}
|
|
741
|
+
${handleMethods.join("\n")}
|
|
742
|
+
private:
|
|
743
|
+
${widgetClassName}* m_owner;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
explicit ${widgetClassName}(QWidget* parent = nullptr);
|
|
747
|
+
~${widgetClassName}() override;
|
|
721
748
|
bool enableDebug();
|
|
722
749
|
static constexpr const char* kBootstrapEntryPoint = "index.html";
|
|
723
750
|
static constexpr const char* kBootstrapContentRoot = "qrc:/${spec.widgetName.toLowerCase()}";
|
|
724
751
|
static constexpr const char* kBootstrapBridgeObject = "${spec.widgetName}Bridge";
|
|
752
|
+
static constexpr int kMaxQueuedCallsPerEndpoint = 1024;
|
|
725
753
|
|
|
726
|
-
|
|
754
|
+
handle handle;
|
|
727
755
|
${publicMethods.map((s) => ` ${s}`).join("\n")}
|
|
728
|
-
|
|
756
|
+
|
|
757
|
+
public slots:
|
|
758
|
+
${slotMethods.map((s) => ` ${s}`).join("\n")}
|
|
759
|
+
${publicSlots.map((s) => ` ${s}`).join("\n")}
|
|
729
760
|
|
|
730
761
|
signals:
|
|
731
762
|
${signals.map((s) => ` ${s}`).join("\n")}
|
|
732
763
|
void diagnosticsForwarded(const QVariantMap& payload);
|
|
733
764
|
|
|
765
|
+
protected:
|
|
766
|
+
void connectNotify(const QMetaMethod& signal) override;
|
|
767
|
+
void disconnectNotify(const QMetaMethod& signal) override;
|
|
768
|
+
|
|
734
769
|
private:
|
|
770
|
+
struct PendingCallInvocation {
|
|
771
|
+
QString requestId;
|
|
772
|
+
QVariantList args;
|
|
773
|
+
QDateTime enqueuedAt;
|
|
774
|
+
};
|
|
735
775
|
struct BridgeBindingRow {
|
|
736
776
|
const char* service;
|
|
737
777
|
const char* member;
|
|
@@ -741,21 +781,37 @@ private:
|
|
|
741
781
|
static constexpr int kBridgeBindingsCount = ${bindings.length};
|
|
742
782
|
static QString makeBindingKey(const QString& service, const QString& member);
|
|
743
783
|
void installBridgeBindings();
|
|
784
|
+
bool hasEmitterListeners(const QString& service, const QString& member) const;
|
|
744
785
|
QVariant handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args);
|
|
745
786
|
void handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args);
|
|
746
787
|
void handleGeneratedInput(const QString& service, const QString& member, const QVariant& value);
|
|
747
|
-
|
|
788
|
+
QVariant waitForCallHandlerAndInvoke(
|
|
789
|
+
const QString& service,
|
|
790
|
+
const QString& member,
|
|
791
|
+
const QString& requestId,
|
|
792
|
+
int timeoutMs,
|
|
793
|
+
const std::function<QVariant()>& invokeNow);
|
|
794
|
+
void removeQueuedCallById(const QString& queueKey, const QString& requestId);
|
|
795
|
+
${callSetterMethods.map((s) => ` ${s}`).join("\n")}
|
|
796
|
+
|
|
797
|
+
qulonglong m_callRequestCounter{0};
|
|
798
|
+
QHash<QString, QQueue<PendingCallInvocation>> m_queuedCalls;
|
|
748
799
|
${fields.map((f) => ` ${f}`).join("\n")}
|
|
749
800
|
};
|
|
750
|
-
|
|
751
|
-
} // namespace ${spec.widgetName}
|
|
752
801
|
`;
|
|
753
802
|
}
|
|
754
803
|
function renderCppStub(spec, cppTypes) {
|
|
804
|
+
const widgetClassName = `${spec.widgetName}Widget`;
|
|
755
805
|
const lines = [];
|
|
756
|
-
lines.push(`#include "include/${spec.widgetName}.h"`);
|
|
806
|
+
lines.push(`#include "include/${spec.widgetName}Widget.h"`);
|
|
757
807
|
lines.push(`#include <QDebug>`);
|
|
808
|
+
lines.push(`#include <QElapsedTimer>`);
|
|
809
|
+
lines.push(`#include <QEventLoop>`);
|
|
758
810
|
lines.push(`#include <QMetaType>`);
|
|
811
|
+
lines.push(`#include <QTimer>`);
|
|
812
|
+
lines.push(`#include <stdexcept>`);
|
|
813
|
+
lines.push("");
|
|
814
|
+
lines.push(`using namespace ${spec.widgetName};`);
|
|
759
815
|
lines.push("");
|
|
760
816
|
lines.push(`extern int qInitResources_${spec.widgetName}();`);
|
|
761
817
|
lines.push("");
|
|
@@ -772,9 +828,23 @@ function renderCppStub(spec, cppTypes) {
|
|
|
772
828
|
lines.push("}");
|
|
773
829
|
lines.push("}");
|
|
774
830
|
lines.push("");
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
831
|
+
for (const service of spec.services) {
|
|
832
|
+
for (const member of service.members) {
|
|
833
|
+
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
834
|
+
continue;
|
|
835
|
+
const pascal = pascalCase(member.name);
|
|
836
|
+
lines.push(`void ${widgetClassName}::handle::${member.name}(const ${pascal}Handler& handler) const {`);
|
|
837
|
+
lines.push(` if (m_owner == nullptr) return;`);
|
|
838
|
+
lines.push(` m_owner->set${pascal}CallHandler(handler);`);
|
|
839
|
+
lines.push(`}`);
|
|
840
|
+
lines.push("");
|
|
841
|
+
lines.push(`void ${widgetClassName}::set${pascal}CallHandler(const ${pascal}Handler& handler) {`);
|
|
842
|
+
lines.push(` m_${member.name}Handler = handler;`);
|
|
843
|
+
lines.push(`}`);
|
|
844
|
+
lines.push("");
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
lines.push(`const ${widgetClassName}::BridgeBindingRow ${widgetClassName}::kBridgeBindings[] = {`);
|
|
778
848
|
for (const service of spec.services) {
|
|
779
849
|
for (const member of service.members) {
|
|
780
850
|
lines.push(` {"${service.name}", "${member.name}", "${member.kind}"},`);
|
|
@@ -782,7 +852,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
782
852
|
}
|
|
783
853
|
lines.push(`};`);
|
|
784
854
|
lines.push("");
|
|
785
|
-
lines.push(`${
|
|
855
|
+
lines.push(`${widgetClassName}::${widgetClassName}(QWidget* parent) : AnQstWebHostBase(parent), handle(this) {`);
|
|
786
856
|
lines.push(` static const bool kResourcesInitialized = []() {`);
|
|
787
857
|
lines.push(` ::qInitResources_${spec.widgetName}();`);
|
|
788
858
|
lines.push(` return true;`);
|
|
@@ -790,7 +860,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
790
860
|
lines.push(` Q_UNUSED(kResourcesInitialized);`);
|
|
791
861
|
lines.push(` registerGeneratedMetaTypes();`);
|
|
792
862
|
lines.push(` installBridgeBindings();`);
|
|
793
|
-
lines.push(` QObject::connect(this, &AnQstWebHostBase::onHostError, this, &${
|
|
863
|
+
lines.push(` QObject::connect(this, &AnQstWebHostBase::onHostError, this, &${widgetClassName}::diagnosticsForwarded);`);
|
|
794
864
|
lines.push(` const bool rootOk = setContentRoot(QString::fromUtf8(kBootstrapContentRoot));`);
|
|
795
865
|
lines.push(` const bool bridgeOk = setBridgeObject(this, QString::fromUtf8(kBootstrapBridgeObject));`);
|
|
796
866
|
lines.push(` const bool loadOk = rootOk && bridgeOk && loadEntryPoint(QString::fromUtf8(kBootstrapEntryPoint));`);
|
|
@@ -799,17 +869,74 @@ function renderCppStub(spec, cppTypes) {
|
|
|
799
869
|
lines.push(` }`);
|
|
800
870
|
lines.push("}");
|
|
801
871
|
lines.push("");
|
|
802
|
-
lines.push(`${
|
|
872
|
+
lines.push(`${widgetClassName}::~${widgetClassName}() = default;`);
|
|
803
873
|
lines.push("");
|
|
804
|
-
lines.push(`bool ${
|
|
874
|
+
lines.push(`bool ${widgetClassName}::enableDebug() {`);
|
|
805
875
|
lines.push(` return AnQstWebHostBase::enableDebug();`);
|
|
806
876
|
lines.push("}");
|
|
807
877
|
lines.push("");
|
|
808
|
-
lines.push(`QString ${
|
|
878
|
+
lines.push(`QString ${widgetClassName}::makeBindingKey(const QString& service, const QString& member) {`);
|
|
809
879
|
lines.push(` return service + QStringLiteral("::") + member;`);
|
|
810
880
|
lines.push(`}`);
|
|
811
881
|
lines.push("");
|
|
812
|
-
lines.push(`void ${
|
|
882
|
+
lines.push(`void ${widgetClassName}::removeQueuedCallById(const QString& queueKey, const QString& requestId) {`);
|
|
883
|
+
lines.push(` if (!m_queuedCalls.contains(queueKey)) return;`);
|
|
884
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
885
|
+
lines.push(` for (int i = 0; i < queue.size(); ++i) {`);
|
|
886
|
+
lines.push(` if (queue[i].requestId == requestId) {`);
|
|
887
|
+
lines.push(` queue.removeAt(i);`);
|
|
888
|
+
lines.push(` break;`);
|
|
889
|
+
lines.push(` }`);
|
|
890
|
+
lines.push(` }`);
|
|
891
|
+
lines.push(`}`);
|
|
892
|
+
lines.push("");
|
|
893
|
+
lines.push(`QVariant ${widgetClassName}::waitForCallHandlerAndInvoke(`);
|
|
894
|
+
lines.push(` const QString& service,`);
|
|
895
|
+
lines.push(` const QString& member,`);
|
|
896
|
+
lines.push(` const QString& requestId,`);
|
|
897
|
+
lines.push(` int timeoutMs,`);
|
|
898
|
+
lines.push(` const std::function<QVariant()>& invokeNow) {`);
|
|
899
|
+
lines.push(` const QString queueKey = makeBindingKey(service, member);`);
|
|
900
|
+
lines.push(` QElapsedTimer timer;`);
|
|
901
|
+
lines.push(` timer.start();`);
|
|
902
|
+
lines.push(` QEventLoop loop;`);
|
|
903
|
+
lines.push(` QTimer tick;`);
|
|
904
|
+
lines.push(` tick.setSingleShot(true);`);
|
|
905
|
+
lines.push(` QObject::connect(&tick, &QTimer::timeout, &loop, &QEventLoop::quit);`);
|
|
906
|
+
lines.push(` while (true) {`);
|
|
907
|
+
lines.push(` if (m_queuedCalls.contains(queueKey) && !m_queuedCalls[queueKey].isEmpty() && m_queuedCalls[queueKey].head().requestId == requestId) {`);
|
|
908
|
+
lines.push(` m_queuedCalls[queueKey].dequeue();`);
|
|
909
|
+
lines.push(` return invokeNow();`);
|
|
910
|
+
lines.push(` }`);
|
|
911
|
+
lines.push(` if (timeoutMs > 0 && timer.elapsed() >= timeoutMs) {`);
|
|
912
|
+
lines.push(` removeQueuedCallById(queueKey, requestId);`);
|
|
913
|
+
lines.push(` return QVariantMap{`);
|
|
914
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("BridgeTimeoutError")},`);
|
|
915
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call timed out while waiting for callback registration.")},`);
|
|
916
|
+
lines.push(` {QStringLiteral("service"), service},`);
|
|
917
|
+
lines.push(` {QStringLiteral("member"), member},`);
|
|
918
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
919
|
+
lines.push(` };`);
|
|
920
|
+
lines.push(` }`);
|
|
921
|
+
lines.push(` tick.start(10);`);
|
|
922
|
+
lines.push(` loop.exec();`);
|
|
923
|
+
lines.push(` }`);
|
|
924
|
+
lines.push(`}`);
|
|
925
|
+
lines.push("");
|
|
926
|
+
lines.push(`bool ${widgetClassName}::hasEmitterListeners(const QString& service, const QString& member) const {`);
|
|
927
|
+
for (const service of spec.services) {
|
|
928
|
+
for (const member of service.members) {
|
|
929
|
+
if (member.kind !== "Emitter")
|
|
930
|
+
continue;
|
|
931
|
+
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
932
|
+
lines.push(` return isSignalConnected(QMetaMethod::fromSignal(&${widgetClassName}::${member.name}));`);
|
|
933
|
+
lines.push(` }`);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
lines.push(` return false;`);
|
|
937
|
+
lines.push(`}`);
|
|
938
|
+
lines.push("");
|
|
939
|
+
lines.push(`void ${widgetClassName}::installBridgeBindings() {`);
|
|
813
940
|
lines.push(` setCallHandler([this](const QString& service, const QString& member, const QVariantList& args) -> QVariant {`);
|
|
814
941
|
lines.push(` return handleGeneratedCall(service, member, args);`);
|
|
815
942
|
lines.push(` });`);
|
|
@@ -821,55 +948,97 @@ function renderCppStub(spec, cppTypes) {
|
|
|
821
948
|
lines.push(` });`);
|
|
822
949
|
lines.push(`}`);
|
|
823
950
|
lines.push("");
|
|
824
|
-
lines.push(`QVariant ${
|
|
951
|
+
lines.push(`QVariant ${widgetClassName}::handleGeneratedCall(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
825
952
|
for (const service of spec.services) {
|
|
826
953
|
for (const member of service.members) {
|
|
827
954
|
if (member.kind !== "Call" || !member.payloadTypeText)
|
|
828
955
|
continue;
|
|
956
|
+
const timeoutMs = member.timeoutMs;
|
|
829
957
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
830
|
-
const pascal = pascalCase(member.name);
|
|
831
958
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
832
|
-
lines.push(` if (!m_${member.name}Handler) {`);
|
|
833
|
-
lines.push(` if (property("anqstDesignerContext").toBool()) {`);
|
|
834
|
-
lines.push(` return ${cppToVariantExpression(cppType, designerPlaceholderCppExpression(cppType, member.name))};`);
|
|
835
|
-
lines.push(` }`);
|
|
836
|
-
lines.push(` return QVariant();`);
|
|
837
|
-
lines.push(` }`);
|
|
838
959
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
839
960
|
const p = member.parameters[i];
|
|
840
961
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
841
962
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
842
963
|
}
|
|
843
|
-
const
|
|
844
|
-
lines.push(` const
|
|
845
|
-
lines.push(`
|
|
964
|
+
lines.push(` const QString requestId = QStringLiteral("call-%1").arg(++m_callRequestCounter);`);
|
|
965
|
+
lines.push(` const QString queueKey = makeBindingKey(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"));`);
|
|
966
|
+
lines.push(` auto invokeNow = [this, requestId${member.parameters.length > 0 ? `, ${member.parameters.map((p) => p.name).join(", ")}` : ""}]() -> QVariant {`);
|
|
967
|
+
lines.push(` if (!m_${member.name}Handler) {`);
|
|
968
|
+
lines.push(` return QVariantMap{`);
|
|
969
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("HandlerNotRegisteredError")},`);
|
|
970
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("No callback registered for Call endpoint.")},`);
|
|
971
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
972
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
973
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
974
|
+
lines.push(` };`);
|
|
975
|
+
lines.push(` }`);
|
|
976
|
+
lines.push(` try {`);
|
|
977
|
+
const callArgs = member.parameters.map((p) => p.name).join(", ");
|
|
978
|
+
lines.push(` const ${cppType} result = m_${member.name}Handler(${callArgs});`);
|
|
979
|
+
lines.push(` return ${cppToVariantExpression(cppType, "result")};`);
|
|
980
|
+
lines.push(` } catch (const std::exception& ex) {`);
|
|
981
|
+
lines.push(` return QVariantMap{`);
|
|
982
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
983
|
+
lines.push(` {QStringLiteral("message"), QString::fromUtf8(ex.what())},`);
|
|
984
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
985
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
986
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
987
|
+
lines.push(` };`);
|
|
988
|
+
lines.push(` } catch (...) {`);
|
|
989
|
+
lines.push(` return QVariantMap{`);
|
|
990
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("CallHandlerError")},`);
|
|
991
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("Call handler threw unknown exception.")},`);
|
|
992
|
+
lines.push(` {QStringLiteral("service"), QStringLiteral("${service.name}")},`);
|
|
993
|
+
lines.push(` {QStringLiteral("member"), QStringLiteral("${member.name}")},`);
|
|
994
|
+
lines.push(` {QStringLiteral("requestId"), requestId}`);
|
|
995
|
+
lines.push(` };`);
|
|
996
|
+
lines.push(` }`);
|
|
997
|
+
lines.push(` };`);
|
|
998
|
+
lines.push(` if (m_${member.name}Handler) {`);
|
|
999
|
+
lines.push(` return invokeNow();`);
|
|
1000
|
+
lines.push(` }`);
|
|
1001
|
+
lines.push(` auto& queue = m_queuedCalls[queueKey];`);
|
|
1002
|
+
lines.push(` if (queue.size() >= kMaxQueuedCallsPerEndpoint) {`);
|
|
1003
|
+
lines.push(` queue.dequeue();`);
|
|
1004
|
+
lines.push(` }`);
|
|
1005
|
+
lines.push(` queue.enqueue(PendingCallInvocation{requestId, args, QDateTime::currentDateTimeUtc()});`);
|
|
1006
|
+
lines.push(` return waitForCallHandlerAndInvoke(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), requestId, ${timeoutMs}, invokeNow);`);
|
|
846
1007
|
lines.push(` }`);
|
|
847
1008
|
}
|
|
848
1009
|
}
|
|
849
|
-
lines.push(` return
|
|
1010
|
+
lines.push(` return QVariantMap{`);
|
|
1011
|
+
lines.push(` {QStringLiteral("code"), QStringLiteral("HandlerNotRegisteredError")},`);
|
|
1012
|
+
lines.push(` {QStringLiteral("message"), QStringLiteral("No Call mapping found.")},`);
|
|
1013
|
+
lines.push(` {QStringLiteral("service"), service},`);
|
|
1014
|
+
lines.push(` {QStringLiteral("member"), member},`);
|
|
1015
|
+
lines.push(` {QStringLiteral("requestId"), QString()}`);
|
|
1016
|
+
lines.push(` };`);
|
|
850
1017
|
lines.push(`}`);
|
|
851
1018
|
lines.push("");
|
|
852
|
-
lines.push(`void ${
|
|
1019
|
+
lines.push(`void ${widgetClassName}::handleGeneratedEmitter(const QString& service, const QString& member, const QVariantList& args) {`);
|
|
1020
|
+
lines.push(` if (!hasEmitterListeners(service, member)) {`);
|
|
1021
|
+
lines.push(` return;`);
|
|
1022
|
+
lines.push(` }`);
|
|
853
1023
|
for (const service of spec.services) {
|
|
854
1024
|
for (const member of service.members) {
|
|
855
1025
|
if (member.kind !== "Emitter")
|
|
856
1026
|
continue;
|
|
857
1027
|
lines.push(` if (service == QStringLiteral("${service.name}") && member == QStringLiteral("${member.name}")) {`);
|
|
858
|
-
lines.push(` if (!m_${member.name}Handler) return;`);
|
|
859
1028
|
for (let i = 0; i < member.parameters.length; i++) {
|
|
860
1029
|
const p = member.parameters[i];
|
|
861
1030
|
const pType = cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name]);
|
|
862
1031
|
lines.push(` const ${pType} ${p.name} = ${variantToCppExpression(pType, `args.value(${i})`)};`);
|
|
863
1032
|
}
|
|
864
1033
|
const argNames = member.parameters.map((p) => p.name).join(", ");
|
|
865
|
-
lines.push(`
|
|
1034
|
+
lines.push(` emit ${member.name}(${argNames});`);
|
|
866
1035
|
lines.push(` return;`);
|
|
867
1036
|
lines.push(` }`);
|
|
868
1037
|
}
|
|
869
1038
|
}
|
|
870
1039
|
lines.push(`}`);
|
|
871
1040
|
lines.push("");
|
|
872
|
-
lines.push(`void ${
|
|
1041
|
+
lines.push(`void ${widgetClassName}::handleGeneratedInput(const QString& service, const QString& member, const QVariant& value) {`);
|
|
873
1042
|
for (const service of spec.services) {
|
|
874
1043
|
for (const member of service.members) {
|
|
875
1044
|
if (member.kind !== "Input" || !member.payloadTypeText)
|
|
@@ -888,20 +1057,8 @@ function renderCppStub(spec, cppTypes) {
|
|
|
888
1057
|
for (const service of spec.services) {
|
|
889
1058
|
for (const member of service.members) {
|
|
890
1059
|
const memberPascal = pascalCase(member.name);
|
|
891
|
-
if (
|
|
892
|
-
lines.push(`void ${
|
|
893
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
894
|
-
lines.push("}");
|
|
895
|
-
lines.push("");
|
|
896
|
-
}
|
|
897
|
-
else if (member.kind === "Emitter") {
|
|
898
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
899
|
-
lines.push(` m_${member.name}Handler = handler;`);
|
|
900
|
-
lines.push("}");
|
|
901
|
-
lines.push("");
|
|
902
|
-
}
|
|
903
|
-
else if (member.kind === "Input" && member.payloadTypeText) {
|
|
904
|
-
lines.push(`void ${spec.widgetName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
1060
|
+
if (member.kind === "Input" && member.payloadTypeText) {
|
|
1061
|
+
lines.push(`void ${widgetClassName}::set${memberPascal}Handler(const ${memberPascal}Handler& handler) {`);
|
|
905
1062
|
lines.push(` m_${member.name}Handler = handler;`);
|
|
906
1063
|
lines.push("}");
|
|
907
1064
|
lines.push("");
|
|
@@ -909,8 +1066,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
909
1066
|
if (member.kind === "Slot") {
|
|
910
1067
|
const ret = member.payloadTypeText ? cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]) : "void";
|
|
911
1068
|
const args = member.parameters.map((p) => `${cppTypes.mapTypeText(p.typeText, [service.name, member.name, p.name])} ${p.name}`).join(", ");
|
|
912
|
-
|
|
913
|
-
lines.push(`${ret} ${spec.widgetName}::${member.name}(${argsWithMeta}) {`);
|
|
1069
|
+
lines.push(`${ret} ${widgetClassName}::slot_${member.name}(${args}) {`);
|
|
914
1070
|
lines.push(` QVariantList invokeArgs;`);
|
|
915
1071
|
for (const p of member.parameters) {
|
|
916
1072
|
const pType = mapTsTypeToCpp(p.typeText);
|
|
@@ -919,14 +1075,18 @@ function renderCppStub(spec, cppTypes) {
|
|
|
919
1075
|
lines.push(` QVariant result;`);
|
|
920
1076
|
lines.push(` QString invokeError;`);
|
|
921
1077
|
lines.push(` const bool success = invokeSlot(QStringLiteral("${service.name}"), QStringLiteral("${member.name}"), invokeArgs, &result, &invokeError);`);
|
|
922
|
-
lines.push(` if (
|
|
923
|
-
lines.push(`
|
|
1078
|
+
lines.push(` if (!success) {`);
|
|
1079
|
+
lines.push(` if (invokeError == QStringLiteral("slot invocation timeout")) {`);
|
|
1080
|
+
lines.push(` const QString timeoutMsg = QStringLiteral("[Timeout] ${service.name}.${member.name}: The webapp inside the widget did not anwser within %1 ms.").arg(slotInvocationTimeoutMs());`);
|
|
1081
|
+
lines.push(` throw std::runtime_error(timeoutMsg.toStdString());`);
|
|
1082
|
+
lines.push(` }`);
|
|
1083
|
+
lines.push(` const QString requestFailed = QStringLiteral("[RequestFailed]: %1").arg(invokeError);`);
|
|
1084
|
+
lines.push(` throw std::runtime_error(requestFailed.toStdString());`);
|
|
1085
|
+
lines.push(` }`);
|
|
924
1086
|
if (ret === "void") {
|
|
925
|
-
lines.push(` if (!success) return;`);
|
|
926
1087
|
lines.push(` return;`);
|
|
927
1088
|
}
|
|
928
1089
|
else {
|
|
929
|
-
lines.push(` if (!success) return ${ret}{};`);
|
|
930
1090
|
lines.push(` return ${variantToCppExpression(ret, "result")};`);
|
|
931
1091
|
}
|
|
932
1092
|
lines.push("}");
|
|
@@ -935,11 +1095,11 @@ function renderCppStub(spec, cppTypes) {
|
|
|
935
1095
|
else if ((member.kind === "Input" || member.kind === "Output") && member.payloadTypeText) {
|
|
936
1096
|
const cppType = cppTypes.mapTypeText(member.payloadTypeText, [service.name, member.name, "Payload"]);
|
|
937
1097
|
const cap = member.name.charAt(0).toUpperCase() + member.name.slice(1);
|
|
938
|
-
lines.push(`${cppType} ${
|
|
1098
|
+
lines.push(`${cppType} ${widgetClassName}::${member.name}() const {`);
|
|
939
1099
|
lines.push(` return m_${member.name};`);
|
|
940
1100
|
lines.push("}");
|
|
941
1101
|
lines.push("");
|
|
942
|
-
lines.push(`void ${
|
|
1102
|
+
lines.push(`void ${widgetClassName}::set${cap}(const ${cppType}& value) {`);
|
|
943
1103
|
lines.push(` if (m_${member.name} == value) return;`);
|
|
944
1104
|
lines.push(` m_${member.name} = value;`);
|
|
945
1105
|
if (member.kind === "Output") {
|
|
@@ -949,7 +1109,7 @@ function renderCppStub(spec, cppTypes) {
|
|
|
949
1109
|
lines.push("}");
|
|
950
1110
|
lines.push("");
|
|
951
1111
|
if (member.kind === "Output") {
|
|
952
|
-
lines.push(`void ${
|
|
1112
|
+
lines.push(`void ${widgetClassName}::${member.name}Slot(const ${cppType}& value) {`);
|
|
953
1113
|
lines.push(` set${cap}(value);`);
|
|
954
1114
|
lines.push(`}`);
|
|
955
1115
|
lines.push("");
|
|
@@ -957,7 +1117,16 @@ function renderCppStub(spec, cppTypes) {
|
|
|
957
1117
|
}
|
|
958
1118
|
}
|
|
959
1119
|
}
|
|
960
|
-
lines.push(`}
|
|
1120
|
+
lines.push(`void ${widgetClassName}::connectNotify(const QMetaMethod& signal) {`);
|
|
1121
|
+
lines.push(` AnQstWebHostBase::connectNotify(signal);`);
|
|
1122
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1123
|
+
lines.push(`}`);
|
|
1124
|
+
lines.push("");
|
|
1125
|
+
lines.push(`void ${widgetClassName}::disconnectNotify(const QMetaMethod& signal) {`);
|
|
1126
|
+
lines.push(` AnQstWebHostBase::disconnectNotify(signal);`);
|
|
1127
|
+
lines.push(` Q_UNUSED(signal);`);
|
|
1128
|
+
lines.push(`}`);
|
|
1129
|
+
lines.push("");
|
|
961
1130
|
return lines.join("\n");
|
|
962
1131
|
}
|
|
963
1132
|
function renderCMake(spec) {
|
|
@@ -977,6 +1146,7 @@ add_library(${spec.widgetName}Widget
|
|
|
977
1146
|
${spec.widgetName}.cpp
|
|
978
1147
|
${spec.widgetName}.qrc
|
|
979
1148
|
include/${spec.widgetName}.h
|
|
1149
|
+
include/${spec.widgetName}Widget.h
|
|
980
1150
|
include/${spec.widgetName}Types.h
|
|
981
1151
|
)
|
|
982
1152
|
target_include_directories(${spec.widgetName}Widget
|
|
@@ -1002,24 +1172,7 @@ function normalizeSlashes(value) {
|
|
|
1002
1172
|
return value.split(node_path_1.default.sep).join("/");
|
|
1003
1173
|
}
|
|
1004
1174
|
function resolveActiveBuildStamp() {
|
|
1005
|
-
|
|
1006
|
-
if (fromEnv && fromEnv.length > 0) {
|
|
1007
|
-
return fromEnv;
|
|
1008
|
-
}
|
|
1009
|
-
const activePath = node_path_1.default.resolve(__dirname, "..", "..", ".anqstgen-version-active.json");
|
|
1010
|
-
if (!node_fs_1.default.existsSync(activePath)) {
|
|
1011
|
-
return "";
|
|
1012
|
-
}
|
|
1013
|
-
try {
|
|
1014
|
-
const parsed = JSON.parse(node_fs_1.default.readFileSync(activePath, "utf8"));
|
|
1015
|
-
if (typeof parsed.active === "string" && parsed.active.trim().length > 0) {
|
|
1016
|
-
return parsed.active.trim();
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
catch {
|
|
1020
|
-
return "";
|
|
1021
|
-
}
|
|
1022
|
-
return "";
|
|
1175
|
+
return build_stamp_1.ANQST_BUILD_STAMP.trim();
|
|
1023
1176
|
}
|
|
1024
1177
|
function withBuildStamp(relativePath, content) {
|
|
1025
1178
|
const stamp = resolveActiveBuildStamp();
|
|
@@ -1114,6 +1267,12 @@ function renderLocalTypeImports(spec) {
|
|
|
1114
1267
|
return "";
|
|
1115
1268
|
return `import type { ${localTypeNames.join(", ")} } from "./types";`;
|
|
1116
1269
|
}
|
|
1270
|
+
function slotHandlerReturnType(tsRet) {
|
|
1271
|
+
if (tsRet === "void") {
|
|
1272
|
+
return "void | Promise<void> | Error";
|
|
1273
|
+
}
|
|
1274
|
+
return `${tsRet} | Promise<${tsRet}> | Error`;
|
|
1275
|
+
}
|
|
1117
1276
|
function renderTsService(spec, serviceName) {
|
|
1118
1277
|
const members = spec.services.find((s) => s.name === serviceName)?.members ?? [];
|
|
1119
1278
|
const fieldLines = [];
|
|
@@ -1137,7 +1296,7 @@ function renderTsService(spec, serviceName) {
|
|
|
1137
1296
|
}
|
|
1138
1297
|
if (m.kind === "Slot") {
|
|
1139
1298
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1140
|
-
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${ret}): void => {`);
|
|
1299
|
+
onSlotMembers.push(` ${m.name}: (handler: (${args}) => ${slotHandlerReturnType(ret)}): void => {`);
|
|
1141
1300
|
onSlotMembers.push(` this._bridge.registerSlot("${serviceName}", "${m.name}", handler as (...args: unknown[]) => unknown);`);
|
|
1142
1301
|
onSlotMembers.push(" },");
|
|
1143
1302
|
continue;
|
|
@@ -1197,7 +1356,7 @@ function renderTsServiceDts(spec, serviceName) {
|
|
|
1197
1356
|
}
|
|
1198
1357
|
if (m.kind === "Slot") {
|
|
1199
1358
|
const ret = mapTypeTextToTs(m.payloadTypeText ?? "void");
|
|
1200
|
-
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${ret}): void;`);
|
|
1359
|
+
onSlotMembers.push(` ${m.name}(handler: (${args}) => ${slotHandlerReturnType(ret)}): void;`);
|
|
1201
1360
|
continue;
|
|
1202
1361
|
}
|
|
1203
1362
|
if ((m.kind === "Input" || m.kind === "Output") && m.payloadTypeText) {
|
|
@@ -1226,7 +1385,7 @@ export declare class ${serviceName} {
|
|
|
1226
1385
|
}
|
|
1227
1386
|
function renderTsServices(spec) {
|
|
1228
1387
|
const serviceClasses = spec.services.map((s) => renderTsService(spec, s.name)).join("\n");
|
|
1229
|
-
const externalTypeImports = renderRequiredTypeImports(spec,
|
|
1388
|
+
const externalTypeImports = renderRequiredTypeImports(spec, `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName)}/services.ts`).trim();
|
|
1230
1389
|
const localTypeImports = renderLocalTypeImports(spec).trim();
|
|
1231
1390
|
const typeImports = [externalTypeImports, localTypeImports].filter((s) => s.length > 0).join("\n");
|
|
1232
1391
|
const typeImportsBlock = typeImports.length > 0 ? `${typeImports}\n\n` : "";
|
|
@@ -1267,6 +1426,24 @@ interface BridgeAdapter {
|
|
|
1267
1426
|
onSlotInvocation(handler: SlotInvocationListener): void;
|
|
1268
1427
|
}
|
|
1269
1428
|
|
|
1429
|
+
function isBridgeCallError(value: unknown): value is {
|
|
1430
|
+
code: unknown;
|
|
1431
|
+
message: unknown;
|
|
1432
|
+
service: unknown;
|
|
1433
|
+
member: unknown;
|
|
1434
|
+
requestId: unknown;
|
|
1435
|
+
} {
|
|
1436
|
+
if (value === null || typeof value !== "object") return false;
|
|
1437
|
+
const row = value as Record<string, unknown>;
|
|
1438
|
+
return (
|
|
1439
|
+
Object.prototype.hasOwnProperty.call(row, "code")
|
|
1440
|
+
&& Object.prototype.hasOwnProperty.call(row, "message")
|
|
1441
|
+
&& Object.prototype.hasOwnProperty.call(row, "service")
|
|
1442
|
+
&& Object.prototype.hasOwnProperty.call(row, "member")
|
|
1443
|
+
&& Object.prototype.hasOwnProperty.call(row, "requestId")
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1270
1447
|
class QtWebChannelAdapter implements BridgeAdapter {
|
|
1271
1448
|
private constructor(private readonly host: HostBridgeApi) {}
|
|
1272
1449
|
|
|
@@ -1300,8 +1477,14 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1300
1477
|
}
|
|
1301
1478
|
|
|
1302
1479
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1303
|
-
return new Promise<T>((resolve) => {
|
|
1304
|
-
this.host.anQstBridge_call(service, member, args, (result) =>
|
|
1480
|
+
return new Promise<T>((resolve, reject) => {
|
|
1481
|
+
this.host.anQstBridge_call(service, member, args, (result) => {
|
|
1482
|
+
if (isBridgeCallError(result)) {
|
|
1483
|
+
reject(result);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
resolve(result as T);
|
|
1487
|
+
});
|
|
1305
1488
|
});
|
|
1306
1489
|
}
|
|
1307
1490
|
|
|
@@ -1331,7 +1514,13 @@ class QtWebChannelAdapter implements BridgeAdapter {
|
|
|
1331
1514
|
}
|
|
1332
1515
|
|
|
1333
1516
|
class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
1334
|
-
private readonly pending = new Map<string,
|
|
1517
|
+
private readonly pending = new Map<string, {
|
|
1518
|
+
service: string;
|
|
1519
|
+
member: string;
|
|
1520
|
+
requestId: string;
|
|
1521
|
+
resolve: (result: unknown) => void;
|
|
1522
|
+
reject: (error: unknown) => void;
|
|
1523
|
+
}>();
|
|
1335
1524
|
private readonly outputListeners: OutputListener[] = [];
|
|
1336
1525
|
private readonly slotListeners: SlotInvocationListener[] = [];
|
|
1337
1526
|
private requestCounter = 0;
|
|
@@ -1343,10 +1532,15 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1343
1532
|
const type = String(message["type"] ?? "");
|
|
1344
1533
|
if (type === "callResult") {
|
|
1345
1534
|
const requestId = String(message["requestId"] ?? "");
|
|
1346
|
-
const
|
|
1347
|
-
if (
|
|
1535
|
+
const pending = this.pending.get(requestId);
|
|
1536
|
+
if (pending) {
|
|
1348
1537
|
this.pending.delete(requestId);
|
|
1349
|
-
|
|
1538
|
+
const result = message["result"];
|
|
1539
|
+
if (isBridgeCallError(result)) {
|
|
1540
|
+
pending.reject(result);
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
pending.resolve(result);
|
|
1350
1544
|
}
|
|
1351
1545
|
return;
|
|
1352
1546
|
}
|
|
@@ -1377,6 +1571,18 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1377
1571
|
this.socket.close();
|
|
1378
1572
|
}
|
|
1379
1573
|
});
|
|
1574
|
+
this.socket.addEventListener("close", () => {
|
|
1575
|
+
for (const pending of this.pending.values()) {
|
|
1576
|
+
pending.reject({
|
|
1577
|
+
code: "BridgeDisconnectedError",
|
|
1578
|
+
message: "Bridge disconnected before call completion.",
|
|
1579
|
+
service: pending.service,
|
|
1580
|
+
member: pending.member,
|
|
1581
|
+
requestId: pending.requestId
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
this.pending.clear();
|
|
1585
|
+
});
|
|
1380
1586
|
}
|
|
1381
1587
|
|
|
1382
1588
|
static async create(): Promise<WebSocketBridgeAdapter> {
|
|
@@ -1408,8 +1614,14 @@ class WebSocketBridgeAdapter implements BridgeAdapter {
|
|
|
1408
1614
|
async call<T>(service: string, member: string, args: unknown[]): Promise<T> {
|
|
1409
1615
|
const requestId = \`req-\${++this.requestCounter}\`;
|
|
1410
1616
|
const payload = { type: "call", requestId, service, member, args };
|
|
1411
|
-
return await new Promise<T>((resolve) => {
|
|
1412
|
-
this.pending.set(requestId,
|
|
1617
|
+
return await new Promise<T>((resolve, reject) => {
|
|
1618
|
+
this.pending.set(requestId, {
|
|
1619
|
+
service,
|
|
1620
|
+
member,
|
|
1621
|
+
requestId,
|
|
1622
|
+
resolve: (value) => resolve(value as T),
|
|
1623
|
+
reject
|
|
1624
|
+
});
|
|
1413
1625
|
this.socket.send(JSON.stringify(payload));
|
|
1414
1626
|
});
|
|
1415
1627
|
}
|
|
@@ -1520,7 +1732,7 @@ class AnQstBridgeRuntime {
|
|
|
1520
1732
|
outputHandler(value);
|
|
1521
1733
|
}
|
|
1522
1734
|
});
|
|
1523
|
-
this.adapter.onSlotInvocation((requestId, service, member, args) => {
|
|
1735
|
+
this.adapter.onSlotInvocation(async (requestId, service, member, args) => {
|
|
1524
1736
|
const key = this.key(service, member);
|
|
1525
1737
|
const handler = this.slotHandlers.get(key);
|
|
1526
1738
|
if (handler === undefined) {
|
|
@@ -1528,10 +1740,15 @@ class AnQstBridgeRuntime {
|
|
|
1528
1740
|
return;
|
|
1529
1741
|
}
|
|
1530
1742
|
try {
|
|
1531
|
-
const result = handler(...args);
|
|
1743
|
+
const result = await Promise.resolve(handler(...args));
|
|
1744
|
+
if (result instanceof Error) {
|
|
1745
|
+
this.adapter!.resolveSlot(requestId, false, undefined, result.message);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1532
1748
|
this.adapter!.resolveSlot(requestId, true, result, "");
|
|
1533
1749
|
} catch (error) {
|
|
1534
|
-
|
|
1750
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1751
|
+
this.adapter!.resolveSlot(requestId, false, undefined, message);
|
|
1535
1752
|
}
|
|
1536
1753
|
});
|
|
1537
1754
|
for (const key of this.slotHandlers.keys()) {
|
|
@@ -1551,13 +1768,13 @@ ${serviceClasses}
|
|
|
1551
1768
|
`;
|
|
1552
1769
|
}
|
|
1553
1770
|
function renderTsTypes(spec) {
|
|
1554
|
-
const typeImports = renderRequiredTypeImports(spec,
|
|
1771
|
+
const typeImports = renderRequiredTypeImports(spec, `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName)}/types.ts`).trim();
|
|
1555
1772
|
const typeDecls = renderTypeDeclarations(spec, true).trim();
|
|
1556
1773
|
const sections = [typeImports, typeDecls].filter((s) => s.length > 0);
|
|
1557
1774
|
return sections.length > 0 ? `${sections.join("\n\n")}\n` : "";
|
|
1558
1775
|
}
|
|
1559
1776
|
function renderTypeServicesDts(spec) {
|
|
1560
|
-
const externalTypeImports = renderRequiredTypeImports(spec,
|
|
1777
|
+
const externalTypeImports = renderRequiredTypeImports(spec, `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName)}/types/services.d.ts`).trim();
|
|
1561
1778
|
const localTypeImports = renderLocalTypeImports(spec).trim();
|
|
1562
1779
|
const serviceDecls = spec.services
|
|
1563
1780
|
.map((s) => renderTsServiceDts(spec, s.name))
|
|
@@ -1566,7 +1783,7 @@ function renderTypeServicesDts(spec) {
|
|
|
1566
1783
|
return sections.length > 0 ? `${sections.join("\n\n")}\n` : "";
|
|
1567
1784
|
}
|
|
1568
1785
|
function renderTypeTypesDts(spec) {
|
|
1569
|
-
const typeImports = renderRequiredTypeImports(spec,
|
|
1786
|
+
const typeImports = renderRequiredTypeImports(spec, `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName)}/types/types.d.ts`).trim();
|
|
1570
1787
|
const typeDecls = renderTypeDeclarations(spec, true).trim();
|
|
1571
1788
|
const sections = [typeImports, typeDecls].filter((s) => s.length > 0);
|
|
1572
1789
|
return sections.length > 0 ? `${sections.join("\n\n")}\n` : "";
|
|
@@ -1632,13 +1849,13 @@ function nodeCap(value) {
|
|
|
1632
1849
|
return value.length === 0 ? value : `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
1633
1850
|
}
|
|
1634
1851
|
function renderNodeExpressWsTypes(spec) {
|
|
1635
|
-
const typeImports = renderRequiredTypeImports(spec,
|
|
1852
|
+
const typeImports = renderRequiredTypeImports(spec, `backend/node/express/${generatedNodeExpressWsDirName(spec.widgetName)}/types/index.d.ts`).trim();
|
|
1636
1853
|
const typeDecls = renderTypeDeclarations(spec, true).trim();
|
|
1637
1854
|
const sections = [typeImports, typeDecls].filter((s) => s.length > 0);
|
|
1638
1855
|
return sections.length > 0 ? `${sections.join("\n\n")}\n` : "";
|
|
1639
1856
|
}
|
|
1640
1857
|
function renderNodeExpressWsIndex(spec) {
|
|
1641
|
-
const typeImports = renderRequiredTypeImports(spec,
|
|
1858
|
+
const typeImports = renderRequiredTypeImports(spec, `backend/node/express/${generatedNodeExpressWsDirName(spec.widgetName)}/index.ts`);
|
|
1642
1859
|
const typeDecls = renderTypeDeclarations(spec, true);
|
|
1643
1860
|
const handlerBridgeTypeName = `${spec.widgetName}HandlerBridge`;
|
|
1644
1861
|
const sessionBridgeTypeName = `${spec.widgetName}SessionBridge`;
|
|
@@ -1764,7 +1981,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1764
1981
|
sendJson(session.socket, {
|
|
1765
1982
|
type: "callResult",
|
|
1766
1983
|
requestId,
|
|
1767
|
-
result: {
|
|
1984
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
1768
1985
|
});
|
|
1769
1986
|
throw err;
|
|
1770
1987
|
}
|
|
@@ -1786,7 +2003,7 @@ function renderNodeExpressWsIndex(spec) {
|
|
|
1786
2003
|
sendJson(session.socket, {
|
|
1787
2004
|
type: "callResult",
|
|
1788
2005
|
requestId,
|
|
1789
|
-
result: {
|
|
2006
|
+
result: { code: "CallHandlerError", message, service, member, requestId }
|
|
1790
2007
|
});
|
|
1791
2008
|
});
|
|
1792
2009
|
return;
|
|
@@ -2138,7 +2355,7 @@ export interface ${spec.widgetName}NodeBridge {
|
|
|
2138
2355
|
export function create${spec.widgetName}NodeExpressWsBridge(options: ${spec.widgetName}NodeBridgeOptions): ${spec.widgetName}NodeBridge {
|
|
2139
2356
|
const wsPath = options.wsPath ?? "/anqst-bridge";
|
|
2140
2357
|
const devConfigPath = options.devConfigPath ?? "/anqst-dev-config.json";
|
|
2141
|
-
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ??
|
|
2358
|
+
const defaultSlotTimeoutMs = options.defaultSlotTimeoutMs ?? 1000;
|
|
2142
2359
|
const maxQueuedPerSlot = options.maxQueuedSlotInvocationsPerSlot ?? 1024;
|
|
2143
2360
|
const sessions = new Map<WebSocket, ${spec.widgetName}NodeSession>();
|
|
2144
2361
|
const diagnosticListeners = new Set<(diagnostic: AnQstDiagnostic) => void>();
|
|
@@ -2230,7 +2447,7 @@ ${callDispatch}
|
|
|
2230
2447
|
sendJson(session.socket, {
|
|
2231
2448
|
type: "callResult",
|
|
2232
2449
|
requestId,
|
|
2233
|
-
result: {
|
|
2450
|
+
result: { code: "HandlerNotRegisteredError", message: err.message, service, member, requestId }
|
|
2234
2451
|
});
|
|
2235
2452
|
throw err;
|
|
2236
2453
|
}
|
|
@@ -2337,32 +2554,34 @@ function renderTypeRootIndexDts(spec) {
|
|
|
2337
2554
|
return sections.length > 0 ? `${sections.join("\n\n")}\n` : "";
|
|
2338
2555
|
}
|
|
2339
2556
|
function generatedCppLibraryDirName(widgetName) {
|
|
2340
|
-
return
|
|
2557
|
+
return (0, layout_1.generatedQtWidgetDirName)(widgetName);
|
|
2341
2558
|
}
|
|
2342
2559
|
function generatedNodeExpressWsDirName(widgetName) {
|
|
2343
|
-
return
|
|
2560
|
+
return (0, layout_1.generatedNodeExpressDirName)(widgetName);
|
|
2344
2561
|
}
|
|
2345
2562
|
function generateOutputs(spec, options = { emitQWidget: true, emitAngularService: true, emitNodeExpressWs: false }) {
|
|
2346
|
-
const
|
|
2347
|
-
const
|
|
2563
|
+
const frontendDir = `frontend/${(0, layout_1.generatedFrontendDirName)(spec.widgetName)}`;
|
|
2564
|
+
const cppDir = `backend/cpp/qt/${generatedCppLibraryDirName(spec.widgetName)}`;
|
|
2565
|
+
const nodeDir = `backend/node/express/${generatedNodeExpressWsDirName(spec.widgetName)}`;
|
|
2348
2566
|
const outputs = {};
|
|
2349
2567
|
if (options.emitAngularService) {
|
|
2350
|
-
outputs[
|
|
2351
|
-
outputs[
|
|
2352
|
-
outputs[
|
|
2353
|
-
outputs[
|
|
2354
|
-
outputs[
|
|
2355
|
-
outputs[
|
|
2356
|
-
outputs[
|
|
2357
|
-
outputs[
|
|
2358
|
-
outputs[
|
|
2359
|
-
outputs[
|
|
2568
|
+
outputs[`${frontendDir}/package.json`] = renderNpmPackage(spec);
|
|
2569
|
+
outputs[`${frontendDir}/index.ts`] = renderTsIndex();
|
|
2570
|
+
outputs[`${frontendDir}/services.ts`] = renderTsServices(spec);
|
|
2571
|
+
outputs[`${frontendDir}/types.ts`] = renderTsTypes(spec);
|
|
2572
|
+
outputs[`${frontendDir}/index.js`] = renderJsIndex();
|
|
2573
|
+
outputs[`${frontendDir}/services.js`] = renderJsServices();
|
|
2574
|
+
outputs[`${frontendDir}/types.js`] = renderJsTypes();
|
|
2575
|
+
outputs[`${frontendDir}/types/index.d.ts`] = renderTypeRootIndexDts(spec);
|
|
2576
|
+
outputs[`${frontendDir}/types/services.d.ts`] = renderTypeServicesDts(spec);
|
|
2577
|
+
outputs[`${frontendDir}/types/types.d.ts`] = renderTypeTypesDts(spec);
|
|
2360
2578
|
}
|
|
2361
2579
|
if (options.emitQWidget) {
|
|
2362
2580
|
const cppTypes = buildCppTypeContext(spec);
|
|
2363
2581
|
outputs[`${cppDir}/CMakeLists.txt`] = renderCMake(spec);
|
|
2364
2582
|
outputs[`${cppDir}/${spec.widgetName}.qrc`] = renderEmbeddedQrc(spec.widgetName, []);
|
|
2365
|
-
outputs[`${cppDir}/include/${spec.widgetName}.h`] =
|
|
2583
|
+
outputs[`${cppDir}/include/${spec.widgetName}.h`] = renderWidgetUmbrellaHeader(spec);
|
|
2584
|
+
outputs[`${cppDir}/include/${spec.widgetName}Widget.h`] = renderWidgetHeader(spec, cppTypes);
|
|
2366
2585
|
outputs[`${cppDir}/include/${spec.widgetName}Types.h`] = renderTypesHeader(spec, cppTypes);
|
|
2367
2586
|
outputs[`${cppDir}/${spec.widgetName}.cpp`] = renderCppStub(spec, cppTypes);
|
|
2368
2587
|
}
|
|
@@ -2374,38 +2593,13 @@ function generateOutputs(spec, options = { emitQWidget: true, emitAngularService
|
|
|
2374
2593
|
return outputs;
|
|
2375
2594
|
}
|
|
2376
2595
|
function writeGeneratedOutputs(cwd, outputs) {
|
|
2377
|
-
const outputRoot =
|
|
2596
|
+
const outputRoot = (0, layout_1.anqstGeneratedRootDir)(cwd);
|
|
2378
2597
|
for (const [relPath, content] of Object.entries(outputs)) {
|
|
2379
2598
|
const filePath = node_path_1.default.join(outputRoot, relPath);
|
|
2380
2599
|
node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), { recursive: true });
|
|
2381
2600
|
node_fs_1.default.writeFileSync(filePath, withBuildStamp(relPath, content), "utf8");
|
|
2382
2601
|
}
|
|
2383
2602
|
}
|
|
2384
|
-
function installTypeScriptOutputs(cwd) {
|
|
2385
|
-
const sourceDir = node_path_1.default.join(cwd, "generated_output", "npmpackage");
|
|
2386
|
-
const targetDir = node_path_1.default.join(cwd, "src", "anqst-generated");
|
|
2387
|
-
if (!node_fs_1.default.existsSync(sourceDir))
|
|
2388
|
-
return;
|
|
2389
|
-
node_fs_1.default.rmSync(targetDir, { recursive: true, force: true });
|
|
2390
|
-
node_fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
2391
|
-
const queue = [sourceDir];
|
|
2392
|
-
while (queue.length > 0) {
|
|
2393
|
-
const current = queue.shift();
|
|
2394
|
-
for (const entry of node_fs_1.default.readdirSync(current, { withFileTypes: true })) {
|
|
2395
|
-
const abs = node_path_1.default.join(current, entry.name);
|
|
2396
|
-
const rel = node_path_1.default.relative(sourceDir, abs);
|
|
2397
|
-
const dst = node_path_1.default.join(targetDir, rel);
|
|
2398
|
-
if (entry.isDirectory()) {
|
|
2399
|
-
node_fs_1.default.mkdirSync(dst, { recursive: true });
|
|
2400
|
-
queue.push(abs);
|
|
2401
|
-
}
|
|
2402
|
-
else if (entry.isFile()) {
|
|
2403
|
-
node_fs_1.default.mkdirSync(node_path_1.default.dirname(dst), { recursive: true });
|
|
2404
|
-
node_fs_1.default.copyFileSync(abs, dst);
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
2603
|
function listFilesRecursively(rootDir) {
|
|
2410
2604
|
const output = [];
|
|
2411
2605
|
const queue = [rootDir];
|
|
@@ -2539,7 +2733,7 @@ function installEmbeddedWebBundle(cwd, widgetName) {
|
|
|
2539
2733
|
if (!node_fs_1.default.existsSync(node_path_1.default.join(distWebRoot, "index.html"))) {
|
|
2540
2734
|
return false;
|
|
2541
2735
|
}
|
|
2542
|
-
const cppLibraryRoot =
|
|
2736
|
+
const cppLibraryRoot = (0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName).cppQtWidgetRoot;
|
|
2543
2737
|
const cppLibraryWebRoot = node_path_1.default.join(cppLibraryRoot, "webapp");
|
|
2544
2738
|
node_fs_1.default.rmSync(cppLibraryWebRoot, { recursive: true, force: true });
|
|
2545
2739
|
node_fs_1.default.mkdirSync(cppLibraryWebRoot, { recursive: true });
|
|
@@ -2571,15 +2765,15 @@ function normalizeEmbeddedIndexHtml(indexPath, webRoot) {
|
|
|
2571
2765
|
node_fs_1.default.writeFileSync(indexPath, html, "utf8");
|
|
2572
2766
|
}
|
|
2573
2767
|
function renderQtIntegrationCMake(widgetName) {
|
|
2574
|
-
const generatedRootVar = "
|
|
2768
|
+
const generatedRootVar = "ANQST_GENERATED_WIDGET_DIR";
|
|
2575
2769
|
const generatedIncludeVar = "ANQST_GENERATED_INCLUDE_DIR";
|
|
2576
|
-
const
|
|
2770
|
+
const projectRootVar = "ANQST_PROJECT_ROOT";
|
|
2577
2771
|
const widgetTarget = `${widgetName}Widget`;
|
|
2578
2772
|
const autogenTarget = `${widgetTarget}_anqst_codegen`;
|
|
2579
2773
|
return `cmake_minimum_required(VERSION 3.21)
|
|
2580
2774
|
|
|
2581
|
-
set(${
|
|
2582
|
-
set(${generatedRootVar} "\${
|
|
2775
|
+
set(${projectRootVar} "\${CMAKE_CURRENT_LIST_DIR}/../../../../..")
|
|
2776
|
+
set(${generatedRootVar} "\${CMAKE_CURRENT_LIST_DIR}/../qt/${generatedCppLibraryDirName(widgetName)}")
|
|
2583
2777
|
set(${generatedIncludeVar} "\${${generatedRootVar}}/include")
|
|
2584
2778
|
|
|
2585
2779
|
if(TARGET ${widgetTarget})
|
|
@@ -2587,7 +2781,7 @@ if(TARGET ${widgetTarget})
|
|
|
2587
2781
|
endif()
|
|
2588
2782
|
|
|
2589
2783
|
if(NOT TARGET anqstwebhostbase)
|
|
2590
|
-
message(FATAL_ERROR "Target 'anqstwebhostbase' must exist before including
|
|
2784
|
+
message(FATAL_ERROR "Target 'anqstwebhostbase' must exist before including generated AnQst CMake for ${widgetName}.")
|
|
2591
2785
|
endif()
|
|
2592
2786
|
|
|
2593
2787
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
|
|
@@ -2603,11 +2797,12 @@ add_custom_command(
|
|
|
2603
2797
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2604
2798
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2605
2799
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2800
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2606
2801
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2607
2802
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2608
2803
|
COMMAND "\${ANQST_NPM_EXECUTABLE}" install
|
|
2609
2804
|
COMMAND "\${ANQST_NPM_EXECUTABLE}" run anqst:build
|
|
2610
|
-
WORKING_DIRECTORY "\${${
|
|
2805
|
+
WORKING_DIRECTORY "\${${projectRootVar}}"
|
|
2611
2806
|
COMMENT "Generating AnQst widget library (${widgetTarget}) from Angular project"
|
|
2612
2807
|
VERBATIM
|
|
2613
2808
|
)
|
|
@@ -2618,6 +2813,7 @@ add_custom_target(${autogenTarget}
|
|
|
2618
2813
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2619
2814
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2620
2815
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2816
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2621
2817
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2622
2818
|
"\${${generatedRootVar}}/webapp/index.html"
|
|
2623
2819
|
)
|
|
@@ -2626,6 +2822,7 @@ set_source_files_properties(
|
|
|
2626
2822
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2627
2823
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2628
2824
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2825
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2629
2826
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2630
2827
|
PROPERTIES GENERATED TRUE
|
|
2631
2828
|
)
|
|
@@ -2634,6 +2831,7 @@ add_library(${widgetTarget}
|
|
|
2634
2831
|
"\${${generatedRootVar}}/${widgetName}.qrc"
|
|
2635
2832
|
"\${${generatedRootVar}}/${widgetName}.cpp"
|
|
2636
2833
|
"\${${generatedIncludeVar}}/${widgetName}.h"
|
|
2834
|
+
"\${${generatedIncludeVar}}/${widgetName}Widget.h"
|
|
2637
2835
|
"\${${generatedIncludeVar}}/${widgetName}Types.h"
|
|
2638
2836
|
)
|
|
2639
2837
|
add_dependencies(${widgetTarget} ${autogenTarget})
|
|
@@ -2648,9 +2846,9 @@ target_link_libraries(${widgetTarget}
|
|
|
2648
2846
|
`;
|
|
2649
2847
|
}
|
|
2650
2848
|
function installQtIntegrationCMake(cwd, widgetName) {
|
|
2651
|
-
const integrationDir =
|
|
2849
|
+
const integrationDir = (0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName).cppCmakeRoot;
|
|
2652
2850
|
node_fs_1.default.mkdirSync(integrationDir, { recursive: true });
|
|
2653
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(integrationDir, "CMakeLists.txt"), withBuildStamp("
|
|
2851
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(integrationDir, "CMakeLists.txt"), withBuildStamp("backend/cpp/cmake/CMakeLists.txt", renderQtIntegrationCMake(widgetName)), "utf8");
|
|
2654
2852
|
}
|
|
2655
2853
|
function normalizeIcoSize(dim) {
|
|
2656
2854
|
return dim === 0 ? 256 : dim;
|
|
@@ -2821,7 +3019,7 @@ function installDesignerPluginIconAssets(cwd, pluginDir) {
|
|
|
2821
3019
|
}
|
|
2822
3020
|
function renderQtDesignerPluginCpp(widgetName, widgetCategory, hasIcon) {
|
|
2823
3021
|
const pluginClass = `${widgetName}DesignerPlugin`;
|
|
2824
|
-
const widgetClass = `${widgetName}
|
|
3022
|
+
const widgetClass = `${widgetName}Widget`;
|
|
2825
3023
|
const groupName = escapeCppStringLiteral(widgetCategory);
|
|
2826
3024
|
const iconExpression = hasIcon
|
|
2827
3025
|
? 'QIcon(QStringLiteral(":/anqstdesignerplugin/plugin-icon.png"))'
|
|
@@ -2881,8 +3079,8 @@ set(CMAKE_AUTOMOC ON)
|
|
|
2881
3079
|
set(CMAKE_AUTOUIC ON)
|
|
2882
3080
|
set(CMAKE_AUTORCC ON)
|
|
2883
3081
|
|
|
2884
|
-
set(
|
|
2885
|
-
set(ANQST_WIDGET_DIR "\${
|
|
3082
|
+
set(ANQST_PROJECT_ROOT "\${CMAKE_CURRENT_LIST_DIR}/../../../../../../..")
|
|
3083
|
+
set(ANQST_WIDGET_DIR "\${CMAKE_CURRENT_LIST_DIR}/..")
|
|
2886
3084
|
set(ANQST_WEBBASE_DIR "" CACHE PATH "Path to AnQstWebBase source directory")
|
|
2887
3085
|
|
|
2888
3086
|
if(NOT EXISTS "\${ANQST_WIDGET_DIR}/CMakeLists.txt")
|
|
@@ -2891,10 +3089,10 @@ endif()
|
|
|
2891
3089
|
|
|
2892
3090
|
if(NOT ANQST_WEBBASE_DIR)
|
|
2893
3091
|
foreach(candidate
|
|
2894
|
-
"\${
|
|
2895
|
-
"\${
|
|
2896
|
-
"\${
|
|
2897
|
-
"\${
|
|
3092
|
+
"\${ANQST_PROJECT_ROOT}/AnQstWidget/AnQstWebBase"
|
|
3093
|
+
"\${ANQST_PROJECT_ROOT}/../AnQstWidget/AnQstWebBase"
|
|
3094
|
+
"\${ANQST_PROJECT_ROOT}/../../AnQstWidget/AnQstWebBase"
|
|
3095
|
+
"\${ANQST_PROJECT_ROOT}/../../../AnQstWidget/AnQstWebBase")
|
|
2898
3096
|
if(EXISTS "\${candidate}/CMakeLists.txt")
|
|
2899
3097
|
set(ANQST_WEBBASE_DIR "\${candidate}")
|
|
2900
3098
|
break()
|
|
@@ -2938,11 +3136,11 @@ set_target_properties(${pluginTarget} PROPERTIES
|
|
|
2938
3136
|
`;
|
|
2939
3137
|
}
|
|
2940
3138
|
function installQtDesignerPluginCMake(cwd, widgetName, options = {}) {
|
|
2941
|
-
const pluginDir =
|
|
3139
|
+
const pluginDir = (0, layout_1.resolveGeneratedLayoutPaths)(cwd, widgetName).designerPluginRoot;
|
|
2942
3140
|
node_fs_1.default.mkdirSync(pluginDir, { recursive: true });
|
|
2943
3141
|
const assets = installDesignerPluginIconAssets(cwd, pluginDir);
|
|
2944
3142
|
const pluginTarget = `${widgetName}DesignerPlugin`;
|
|
2945
3143
|
const widgetCategory = options.widgetCategory ?? "AnQst Widgets";
|
|
2946
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(pluginDir, "CMakeLists.txt"), withBuildStamp(
|
|
2947
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(pluginDir, `${pluginTarget}.cpp`), withBuildStamp(`
|
|
3144
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(pluginDir, "CMakeLists.txt"), withBuildStamp(`backend/cpp/qt/${generatedCppLibraryDirName(widgetName)}/designerPlugin/CMakeLists.txt`, renderQtDesignerPluginCMake(widgetName, assets.hasIcon)), "utf8");
|
|
3145
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(pluginDir, `${pluginTarget}.cpp`), withBuildStamp(`backend/cpp/qt/${generatedCppLibraryDirName(widgetName)}/designerPlugin/${pluginTarget}.cpp`, renderQtDesignerPluginCpp(widgetName, widgetCategory, assets.hasIcon)), "utf8");
|
|
2948
3146
|
}
|