libmodulor 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +19 -0
- package/CHANGELOG.md +35 -1
- package/README.md +10 -4
- package/dist/esm/app/workers/AppSrcFilePathBuilder.d.ts +16 -0
- package/dist/esm/app/workers/AppSrcFilePathBuilder.js +6 -4
- package/dist/esm/apps/Helper/index.js +1 -0
- package/dist/esm/apps/Helper/src/i18n.js +4 -0
- package/dist/esm/apps/Helper/src/lib/project.d.ts +2 -0
- package/dist/esm/apps/Helper/src/lib/project.js +120 -0
- package/dist/esm/apps/Helper/src/manifest.d.ts +5 -0
- package/dist/esm/apps/Helper/src/manifest.js +5 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +15 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +118 -0
- package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.js +3 -2
- package/dist/esm/bundlers/vite/StripUCDLifecycleServerPlugin.js +3 -0
- package/dist/esm/convention.d.ts +1 -0
- package/dist/esm/convention.js +17 -4
- package/dist/esm/dt/Validation.d.ts +8 -0
- package/dist/esm/dt/Validation.js +8 -0
- package/dist/esm/dt/base/TBase.d.ts +2 -1
- package/dist/esm/dt/base/TBoolean.js +2 -0
- package/dist/esm/dt/base/TInt.js +3 -0
- package/dist/esm/dt/base/TNumber.js +2 -0
- package/dist/esm/dt/base/TObject.d.ts +15 -0
- package/dist/esm/dt/base/TObject.js +14 -0
- package/dist/esm/dt/base/TString.js +1 -1
- package/dist/esm/dt/final/TAmount.js +1 -0
- package/dist/esm/dt/final/TCountryISO3166Alpha2.js +1 -0
- package/dist/esm/dt/final/TCurrencyISO4217.js +1 -0
- package/dist/esm/dt/final/TDateTimeFormat.js +1 -0
- package/dist/esm/dt/final/TEmail.js +2 -0
- package/dist/esm/dt/final/TEmoji.js +4 -0
- package/dist/esm/dt/final/TFile.js +3 -0
- package/dist/esm/dt/final/THostAddress.js +2 -0
- package/dist/esm/dt/final/TIPv6.js +1 -0
- package/dist/esm/dt/final/TJWT.js +8 -0
- package/dist/esm/dt/final/TPercentage.js +5 -0
- package/dist/esm/dt/final/TSQLQuery.js +1 -0
- package/dist/esm/dt/final/TSSHPrivateKey.js +3 -1
- package/dist/esm/dt/final/TSemVerVersion.js +1 -0
- package/dist/esm/dt/final/TShellCommand.js +1 -0
- package/dist/esm/dt/final/TURL.js +2 -0
- package/dist/esm/dt/final/TUUID.js +1 -0
- package/dist/esm/dt/final/TYesNo.js +1 -1
- package/dist/esm/dt/index.d.ts +1 -1
- package/dist/esm/i18n/WordingManager.d.ts +16 -0
- package/dist/esm/i18n/types.d.ts +5 -0
- package/dist/esm/icon/Icon.d.ts +7 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.node.d.ts +1 -0
- package/dist/esm/index.node.js +1 -0
- package/dist/esm/index.react.d.ts +1 -1
- package/dist/esm/product/manifest.d.ts +15 -0
- package/dist/esm/products/Helper/container.js +4 -0
- package/dist/esm/products/Helper/index.js +5 -0
- package/dist/esm/products/Helper/manifest.d.ts +6 -1
- package/dist/esm/std/BufferManager.d.ts +18 -0
- package/dist/esm/std/ClockManager.d.ts +5 -0
- package/dist/esm/std/EnvironmentManager.d.ts +10 -0
- package/dist/esm/std/HTTPAPICaller.d.ts +6 -0
- package/dist/esm/std/I18nManager.d.ts +26 -0
- package/dist/esm/std/JWTManager.d.ts +26 -0
- package/dist/esm/std/JobManager.d.ts +6 -0
- package/dist/esm/std/LLMManager.d.ts +25 -0
- package/dist/esm/std/LLMManager.js +1 -0
- package/dist/esm/std/PromptManager.d.ts +8 -0
- package/dist/esm/std/SettingsManager.d.ts +19 -0
- package/dist/esm/std/SettingsManager.js +9 -0
- package/dist/esm/std/ShellCommandExecutor.d.ts +19 -0
- package/dist/esm/std/ShellCommandExecutor.js +1 -0
- package/dist/esm/std/impl/ConsoleLogger.js +7 -1
- package/dist/esm/std/impl/FakeEmailManager.js +1 -0
- package/dist/esm/std/impl/FakeJobManager.js +1 -0
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.d.ts +9 -0
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +11 -0
- package/dist/esm/std/impl/MistralAILLMManager.d.ts +17 -0
- package/dist/esm/std/impl/MistralAILLMManager.js +56 -0
- package/dist/esm/std/impl/NodeCryptoManager.js +6 -1
- package/dist/esm/std/impl/NodeDeterministicCryptoManager.d.ts +14 -0
- package/dist/esm/std/impl/NodeDeterministicCryptoManager.js +17 -3
- package/dist/esm/std/impl/NodeFSManager.js +10 -0
- package/dist/esm/std/impl/NodeHTTPAPICallExecutorAgentBuilder.js +2 -0
- package/dist/esm/std/impl/NodePromptManager.js +3 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.d.ts +4 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.js +41 -0
- package/dist/esm/std/impl/OllamaLLMManager.d.ts +20 -0
- package/dist/esm/std/impl/OllamaLLMManager.js +56 -0
- package/dist/esm/std/impl/OpenAILLMManager.d.ts +17 -0
- package/dist/esm/std/impl/OpenAILLMManager.js +51 -0
- package/dist/esm/std/impl/SimpleHTTPAPICaller.js +14 -0
- package/dist/esm/std/impl/SimpleMapI18nManager.js +4 -2
- package/dist/esm/std/impl/StdDateClockManager.js +3 -0
- package/dist/esm/std/impl/UCDataStoreExternalResourceManager.js +3 -0
- package/dist/esm/std/impl/WebCryptoManager.js +9 -0
- package/dist/esm/std/index.d.ts +2 -0
- package/dist/esm/std/index.js +2 -0
- package/dist/esm/target/lib/cli/renderer.js +3 -0
- package/dist/esm/target/lib/client/consts.d.ts +3 -0
- package/dist/esm/target/lib/client/consts.js +3 -0
- package/dist/esm/target/lib/mcp-server/MCPServerBooter.js +1 -0
- package/dist/esm/target/lib/react/UCContainer.js +1 -0
- package/dist/esm/target/lib/react/UCPanel.js +4 -0
- package/dist/esm/target/lib/react/form.d.ts +26 -2
- package/dist/esm/target/lib/react/form.js +18 -1
- package/dist/esm/target/lib/react/useUC.d.ts +8 -0
- package/dist/esm/target/lib/react/useUC.js +22 -0
- package/dist/esm/target/lib/react/useUCOR.d.ts +15 -0
- package/dist/esm/target/lib/react/useUCOR.js +45 -0
- package/dist/esm/target/lib/rn/input.d.ts +7 -0
- package/dist/esm/target/lib/rn/input.js +2 -0
- package/dist/esm/target/lib/server/AuthenticationChecker.js +2 -1
- package/dist/esm/target/lib/server/BasicAuthenticationChecker.js +1 -0
- package/dist/esm/target/lib/server/CSPDirectivesBuilder.js +13 -0
- package/dist/esm/target/lib/server/CustomerFacingErrorBuilder.js +3 -0
- package/dist/esm/target/lib/server/PrivateApiKeyAuthenticationChecker.js +1 -0
- package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
- package/dist/esm/target/lib/server/RequestChecker.js +5 -4
- package/dist/esm/target/lib/server/RequestHandler.d.ts +5 -0
- package/dist/esm/target/lib/server/RequestLogger.js +5 -0
- package/dist/esm/target/lib/server/ServerManager.d.ts +19 -0
- package/dist/esm/target/lib/server/consts.d.ts +3 -0
- package/dist/esm/target/lib/server/consts.js +3 -0
- package/dist/esm/target/lib/web/input.d.ts +21 -0
- package/dist/esm/target/lib/web/input.js +4 -0
- package/dist/esm/target/node-core-cli/NodeCoreCLIManager.js +2 -2
- package/dist/esm/target/node-express-server/NodeExpressServerManager.js +5 -0
- package/dist/esm/target/node-express-server/lib/AuthCookieCreator.js +1 -1
- package/dist/esm/target/node-express-server/middlewares/AuthenticationCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/PublicApiKeyCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/RequestCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/RequestHandlerMiddlewareBuilder.js +8 -0
- package/dist/esm/target/node-express-server/middlewares/RequestLoggerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.d.ts +10 -0
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +14 -0
- package/dist/esm/target/react-native-pure/UCForm.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-native-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +9 -8
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +2 -7
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +1 -1
- package/dist/esm/target/react-web-pure/UCForm.js +1 -1
- package/dist/esm/target/react-web-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-web-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +20 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.js +3 -3
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.d.ts +2 -4
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.js +1 -1
- package/dist/esm/testing/AppTester.d.ts +4 -0
- package/dist/esm/testing/AppTester.js +16 -0
- package/dist/esm/testing/AppTesterConfigurator.d.ts +68 -0
- package/dist/esm/testing/UCDataStoreTester.d.ts +9 -0
- package/dist/esm/testing/UCDataStoreTester.js +13 -0
- package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +22 -2
- package/dist/esm/testing/impl/SimpleAppTesterConfigurator.js +1 -0
- package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +9 -3
- package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +12 -4
- package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -0
- package/dist/esm/testing/opts.d.ts +38 -0
- package/dist/esm/testing/opts.js +1 -1
- package/dist/esm/testing/uc-input.js +2 -0
- package/dist/esm/testing/workers/AppTesterCtxInitializer.js +7 -0
- package/dist/esm/testing/workers/UCExecutor.js +1 -0
- package/dist/esm/testing/workers/checkers/AppIndexChecker.js +1 -0
- package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +4 -0
- package/dist/esm/uc/UC.js +19 -1
- package/dist/esm/uc/UCInputField.d.ts +28 -0
- package/dist/esm/uc/UCInputField.js +42 -0
- package/dist/esm/uc/data.d.ts +3 -0
- package/dist/esm/uc/def.d.ts +7 -0
- package/dist/esm/uc/exec.d.ts +39 -0
- package/dist/esm/uc/exec.js +29 -0
- package/dist/esm/uc/ext.d.ts +30 -1
- package/dist/esm/uc/helpers/UCOutputBuilder.js +5 -0
- package/dist/esm/uc/helpers/UCOutputReader.js +3 -1
- package/dist/esm/uc/impl/HTTPUCTransporter.js +4 -0
- package/dist/esm/uc/impl/InMemoryUCDataStore.js +7 -0
- package/dist/esm/uc/impl/KnexUCDataStore.d.ts +4 -0
- package/dist/esm/uc/impl/KnexUCDataStore.js +14 -0
- package/dist/esm/uc/impl/SimpleUCManager.js +6 -0
- package/dist/esm/uc/input-field.d.ts +60 -0
- package/dist/esm/uc/input-field.js +33 -0
- package/dist/esm/uc/input.d.ts +24 -0
- package/dist/esm/uc/lifecycle/client/IdleClientMain.js +1 -0
- package/dist/esm/uc/lifecycle/server/IdleServerMain.js +2 -0
- package/dist/esm/uc/manager.d.ts +11 -0
- package/dist/esm/uc/metadata.d.ts +10 -0
- package/dist/esm/uc/opi-layout.d.ts +3 -0
- package/dist/esm/uc/opi.d.ts +8 -0
- package/dist/esm/uc/output-field.d.ts +9 -0
- package/dist/esm/uc/output-part.d.ts +22 -0
- package/dist/esm/uc/output.d.ts +3 -0
- package/dist/esm/uc/policies/RoleRegularUCPolicy.js +1 -0
- package/dist/esm/uc/policies/funcs.js +1 -0
- package/dist/esm/uc/policy.d.ts +22 -0
- package/dist/esm/uc/sec.d.ts +9 -0
- package/dist/esm/uc/server.d.ts +10 -0
- package/dist/esm/uc/settings.d.ts +25 -0
- package/dist/esm/uc/side-effect.d.ts +16 -0
- package/dist/esm/uc/side-effect.js +16 -0
- package/dist/esm/uc/utils/rInput.d.ts +12 -0
- package/dist/esm/uc/utils/rInput.js +2 -0
- package/dist/esm/uc/utils/rVal.d.ts +25 -0
- package/dist/esm/uc/utils/rVal.js +27 -0
- package/dist/esm/uc/utils/recIs.d.ts +9 -0
- package/dist/esm/uc/utils/recIs.js +12 -1
- package/dist/esm/uc/utils/stripUCDLifecycleServer.d.ts +13 -0
- package/dist/esm/uc/utils/stripUCDLifecycleServer.js +17 -0
- package/dist/esm/uc/utils/ucifcoIsForArray.d.ts +6 -0
- package/dist/esm/uc/utils/ucifcoIsForArray.js +6 -0
- package/dist/esm/uc/workers/SimpleAggregateFinder.d.ts +12 -0
- package/dist/esm/uc/workers/SimpleAggregateFinder.js +12 -0
- package/dist/esm/uc/workers/UCBuilder.d.ts +7 -0
- package/dist/esm/uc/workers/UCBuilder.js +7 -0
- package/dist/esm/uc/workers/UCExecChecker.js +2 -0
- package/dist/esm/uc/workers/UCInputFilesProcessor.js +10 -4
- package/dist/esm/uc/workers/UCOutputFilesProcessor.js +6 -2
- package/dist/esm/utils/async/sleep.d.ts +10 -0
- package/dist/esm/utils/async/sleep.js +10 -0
- package/dist/esm/utils/http/appendData.js +5 -1
- package/dist/esm/utils/ioc/ContainerPrinter.js +2 -0
- package/dist/esm/utils/ioc/bindCommon.js +4 -0
- package/dist/esm/utils/ioc/bindNodeCLI.js +2 -0
- package/dist/esm/utils/ioc/bindNodeCore.js +1 -0
- package/dist/esm/utils/ioc/bindProduct.js +2 -0
- package/dist/esm/utils/ioc/bindRN.js +1 -0
- package/dist/esm/utils/ioc/bindServer.js +1 -0
- package/dist/esm/utils/ioc/bindWeb.js +2 -0
- package/dist/esm/utils/ioc/container.js +6 -0
- package/dist/esm/utils/numbers/units.js +3 -0
- package/dist/esm/utils/types/funcs.d.ts +35 -0
- package/dist/esm/utils/types/funcs.js +35 -0
- package/dist/esm/utils/types/utility-types.d.ts +17 -0
- package/dist/esm/utils/types/utility-types.js +1 -0
- package/package.json +13 -14
|
@@ -4,31 +4,46 @@ import { htmlInputDef } from '../lib/web/input.js';
|
|
|
4
4
|
const CHECKED_FIELD_TYPES = ['checkbox', 'radio'];
|
|
5
5
|
const FILE_FIELD_TYPES = ['file'];
|
|
6
6
|
const MULTIPLE_VALUES_SEPARATOR = ',';
|
|
7
|
-
export function UCFormFieldControl({ errMsg = null, execState,
|
|
8
|
-
const attrs = htmlInputDef(
|
|
7
|
+
export function UCFormFieldControl({ errMsg = null, execState, f, onChange: onChangeBase, }) {
|
|
8
|
+
const attrs = htmlInputDef(f, execState, errMsg);
|
|
9
9
|
const onChange = (e) => {
|
|
10
10
|
const target = e.currentTarget;
|
|
11
11
|
const type = target.type;
|
|
12
12
|
let value = target.value;
|
|
13
|
+
if (target.localName === 'select' && !value) {
|
|
14
|
+
// Prevent the value from being '' when we set/unset the select
|
|
15
|
+
// Otherwise it sets '' as value and prevents the form for being valid
|
|
16
|
+
onChangeBase(f, UCInputFieldChangeOperator.RESET, value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
13
19
|
if (CHECKED_FIELD_TYPES.includes(type) && 'checked' in target) {
|
|
14
20
|
value = target.checked;
|
|
15
21
|
}
|
|
16
22
|
else if (FILE_FIELD_TYPES.includes(type) && 'files' in target) {
|
|
17
23
|
value = target.files?.item(0);
|
|
18
24
|
}
|
|
19
|
-
const [isRepeatable] = ucifRepeatability(
|
|
25
|
+
const [isRepeatable] = ucifRepeatability(f.def);
|
|
20
26
|
if (isRepeatable && typeof value === 'string') {
|
|
21
27
|
const valueArr = value
|
|
22
28
|
.split(MULTIPLE_VALUES_SEPARATOR)
|
|
23
29
|
.map((v) => v.trim());
|
|
24
|
-
onChangeBase(
|
|
30
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, valueArr);
|
|
25
31
|
}
|
|
26
32
|
else {
|
|
27
|
-
onChangeBase(
|
|
33
|
+
onChangeBase(f, UCInputFieldChangeOperator.SET, value);
|
|
28
34
|
}
|
|
29
35
|
};
|
|
30
36
|
if (attrs.internal?.multiline) {
|
|
31
37
|
return React.createElement("textarea", { ...attrs.spec, onChange: onChange });
|
|
32
38
|
}
|
|
39
|
+
const { type } = f.def;
|
|
40
|
+
const options = type.getOptions();
|
|
41
|
+
if (options) {
|
|
42
|
+
// TODO : Handle type.hasStrictOptions() => display an input text alongside the select
|
|
43
|
+
// TODO : Consider using a radio and/or checkbox and/or selectable buttons when the options count < X
|
|
44
|
+
return (React.createElement("select", { ...attrs.spec, onChange: onChange },
|
|
45
|
+
React.createElement("option", null),
|
|
46
|
+
options.map((o) => (React.createElement("option", { key: o.value.toString(), value: o.value.toString() }, o.label)))));
|
|
47
|
+
}
|
|
33
48
|
return React.createElement("input", { ...attrs.spec, onChange: onChange });
|
|
34
49
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldDesc<T extends DataType>({ field, }: Props<T>): ReactElement | null;
|
|
3
|
+
import type { UCFormFieldDescProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldDesc<T extends DataType>({ f, }: UCFormFieldDescProps<T>): ReactElement | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
export function UCFormFieldDesc({
|
|
3
|
+
export function UCFormFieldDesc({ f, }) {
|
|
4
4
|
const { wordingManager } = useDIContext();
|
|
5
|
-
const { desc } = wordingManager.ucif(
|
|
5
|
+
const { desc } = wordingManager.ucif(f);
|
|
6
6
|
if (!desc) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
errMsg: ErrorMessage;
|
|
5
|
-
}
|
|
6
|
-
export declare function UCFormFieldErr({ errMsg }: Props): ReactElement;
|
|
7
|
-
export {};
|
|
2
|
+
import type { UCFormFieldErrProps } from '../lib/react/form.js';
|
|
3
|
+
export declare function UCFormFieldErr({ errMsg }: UCFormFieldErrProps): ReactElement;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { DataType } from '../../dt/index.js';
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
field: UCInputField<T>;
|
|
6
|
-
}
|
|
7
|
-
export declare function UCFormFieldLabel<T extends DataType>({ field, }: Props<T>): ReactElement;
|
|
3
|
+
import type { UCFormFieldLabelProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormFieldLabel<T extends DataType>({ f, }: UCFormFieldLabelProps<T>): ReactElement;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { ucifId } from '../../uc/index.js';
|
|
3
3
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
-
export function UCFormFieldLabel({
|
|
4
|
+
export function UCFormFieldLabel({ f, }) {
|
|
5
5
|
const { wordingManager } = useDIContext();
|
|
6
|
-
const { label } = wordingManager.ucif(
|
|
7
|
-
return React.createElement("label", { htmlFor: ucifId(
|
|
6
|
+
const { label } = wordingManager.ucif(f);
|
|
7
|
+
return React.createElement("label", { htmlFor: ucifId(f.key) }, label);
|
|
8
8
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, uc }: Props<I, OPI0, OPI1>): ReactElement;
|
|
6
|
-
export {};
|
|
3
|
+
import type { UCFormSubmitControlProps } from '../lib/react/form.js';
|
|
4
|
+
export declare function UCFormSubmitControl<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ execState, disabled, uc, }: UCFormSubmitControlProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, {} from 'react';
|
|
2
2
|
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
3
|
-
export function UCFormSubmitControl({ execState, disabled, uc }) {
|
|
3
|
+
export function UCFormSubmitControl({ execState, disabled, uc, }) {
|
|
4
4
|
const { wordingManager } = useDIContext();
|
|
5
5
|
return (React.createElement("input", { disabled: disabled, type: "submit", value: wordingManager.ucISubmit(uc.def, execState) }));
|
|
6
6
|
}
|
|
@@ -43,6 +43,10 @@ export declare class AppTester {
|
|
|
43
43
|
private ucExecutor;
|
|
44
44
|
private configurator;
|
|
45
45
|
private ctx;
|
|
46
|
+
/**
|
|
47
|
+
* We use a "safe" one to avoid any "infinite loop" while trying to import/resolve a file.
|
|
48
|
+
* This can happen in case of circular dependencies for example.
|
|
49
|
+
*/
|
|
46
50
|
private safeSrcImporter;
|
|
47
51
|
private testResults;
|
|
48
52
|
private testSummary;
|
|
@@ -14,6 +14,8 @@ import { inject, injectable } from 'inversify';
|
|
|
14
14
|
import { I18nEN } from '../i18n/locales/en.js';
|
|
15
15
|
import { I18nFR } from '../i18n/locales/fr.js';
|
|
16
16
|
import { FAKE_USER_ADMIN, UCBuilder, UCInputFieldChangeOperator, ucHTTPContract, } from '../uc/index.js';
|
|
17
|
+
// We inject directly the implementation because we'll generate all the reports and not only the one that is bound to the interface.
|
|
18
|
+
// We can plan a setting à la Vitest where we specify the types of reports to generate though.
|
|
17
19
|
import { SimpleHTMLAppTestReportEmitter } from './impl/SimpleHTMLAppTestReportEmitter.js';
|
|
18
20
|
import { optsAllSet } from './opts.js';
|
|
19
21
|
import { defaultUCAuthSetters } from './uc-auth.js';
|
|
@@ -40,7 +42,12 @@ let AppTester = class AppTester {
|
|
|
40
42
|
ucExecutor;
|
|
41
43
|
configurator;
|
|
42
44
|
ctx;
|
|
45
|
+
/**
|
|
46
|
+
* We use a "safe" one to avoid any "infinite loop" while trying to import/resolve a file.
|
|
47
|
+
* This can happen in case of circular dependencies for example.
|
|
48
|
+
*/
|
|
43
49
|
safeSrcImporter;
|
|
50
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
44
51
|
testResults;
|
|
45
52
|
testSummary;
|
|
46
53
|
ucDefSourcesCheckerOutput;
|
|
@@ -134,7 +141,9 @@ let AppTester = class AppTester {
|
|
|
134
141
|
const inputFiller = (uc) => {
|
|
135
142
|
uc.fill(input);
|
|
136
143
|
};
|
|
144
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
137
145
|
const { out } = await this.execUC({
|
|
146
|
+
// TODO : Pass the appropriate one so we test the real flow and not the auth
|
|
138
147
|
auth: FAKE_USER_ADMIN,
|
|
139
148
|
authName: 'ADMIN',
|
|
140
149
|
inputFiller,
|
|
@@ -148,6 +157,7 @@ let AppTester = class AppTester {
|
|
|
148
157
|
...input,
|
|
149
158
|
appManifest: this.ctx.appManifest,
|
|
150
159
|
});
|
|
160
|
+
// TODO : Add errors mapping to configurator so the developer can override this default behavior
|
|
151
161
|
let status = 'warning';
|
|
152
162
|
if (!out.err) {
|
|
153
163
|
status = 'success';
|
|
@@ -169,6 +179,9 @@ let AppTester = class AppTester {
|
|
|
169
179
|
let sideEffects = await this.configurator.sideEffects(this.ctx);
|
|
170
180
|
if (flow) {
|
|
171
181
|
name = `${flow.name} > ${name}`;
|
|
182
|
+
// For regular uc tests, side effects are cleared between each execution
|
|
183
|
+
// But it's not the case for a flow, thus each flow uc test shares the same side effects ref
|
|
184
|
+
// To have the side effects at each stage, we take a snapshot (to be improved as this is not performant at all)
|
|
172
185
|
if (sideEffects) {
|
|
173
186
|
const snapshot = JSON.parse(JSON.stringify(Array.from(sideEffects.entries())));
|
|
174
187
|
sideEffects = new Map(snapshot);
|
|
@@ -205,6 +218,7 @@ let AppTester = class AppTester {
|
|
|
205
218
|
async init({ appPath, configurator, serverClientSettings, srcImporter, }) {
|
|
206
219
|
this.configurator = configurator;
|
|
207
220
|
this.safeSrcImporter = (path) => Promise.race([
|
|
221
|
+
// We can cast because it fails or looses the race.
|
|
208
222
|
awaitForSrcImport(path),
|
|
209
223
|
srcImporter(path),
|
|
210
224
|
]);
|
|
@@ -222,6 +236,7 @@ let AppTester = class AppTester {
|
|
|
222
236
|
await this.initServer();
|
|
223
237
|
}
|
|
224
238
|
async ucTestData(ucdRef) {
|
|
239
|
+
// Auth setters
|
|
225
240
|
const defaultASs = defaultUCAuthSetters();
|
|
226
241
|
let asEntries = Object.entries(defaultASs);
|
|
227
242
|
const asConfig = await this.configurator.authSettersConfig();
|
|
@@ -236,6 +251,7 @@ let AppTester = class AppTester {
|
|
|
236
251
|
asEntries.push(...Object.entries(add));
|
|
237
252
|
}
|
|
238
253
|
}
|
|
254
|
+
// Input fillers
|
|
239
255
|
const defaultIFs = defaultUCInputFillers();
|
|
240
256
|
const ifEntries = Object.entries(defaultIFs);
|
|
241
257
|
const specificIFs = await this.configurator.inputFillers();
|
|
@@ -6,21 +6,89 @@ import type { DefaultUCAuthSetter, UCAuthSetterSet } from './uc-auth.js';
|
|
|
6
6
|
import type { CustomUCInputFiller, UCInputFillerSet } from './uc-input.js';
|
|
7
7
|
import type { UCExecutorAssertion } from './workers/UCExecutor.js';
|
|
8
8
|
export type AppTesterConfiguratorAuthSettersConfig = {
|
|
9
|
+
/**
|
|
10
|
+
* Specific auth setters to add to the default ones
|
|
11
|
+
*/
|
|
9
12
|
add?: UCAuthSetterSet;
|
|
13
|
+
/**
|
|
14
|
+
* Default auth setters to exclude
|
|
15
|
+
*
|
|
16
|
+
* For instance, if your app does not care about auth (e.g. only client side app), you can safely exclude everything except {@link ANONYMOUS}
|
|
17
|
+
*/
|
|
10
18
|
exclude?: Set<DefaultUCAuthSetter>;
|
|
11
19
|
};
|
|
12
20
|
export type AppTesterConfiguratorInputFillers<I extends UCInput = any, OPI0 extends UCOPIBase = any, OPI1 extends UCOPIBase = any> = Map<UCName, UCInputFillerSet<CustomUCInputFiller, I, OPI0, OPI1>>;
|
|
13
21
|
export type AppTesterConfiguratorSideEffects = Map<string, any>;
|
|
14
22
|
export type AppTesterConfiguratorSideEffectsSerialized = [string, any][];
|
|
15
23
|
export type AppTesterConfiguratorSpecificAssertions<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Map<CryptoManagerHash, UCExecutorAssertion<I, OPI0, OPI1>>;
|
|
24
|
+
/**
|
|
25
|
+
* Configure the tester for a specific app
|
|
26
|
+
*
|
|
27
|
+
* @defaultValue See {@link SimpleAppTesterConfigurator}
|
|
28
|
+
*/
|
|
16
29
|
export interface AppTesterConfigurator {
|
|
30
|
+
/**
|
|
31
|
+
* Auth setters config to add some or exclude default ones
|
|
32
|
+
*/
|
|
17
33
|
authSettersConfig(): Promise<AppTesterConfiguratorAuthSettersConfig | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Override the implementations needed by the use cases, in `ctx.container`
|
|
36
|
+
*
|
|
37
|
+
* @param ctx
|
|
38
|
+
*/
|
|
18
39
|
bindImplementations(ctx: AppTesterCtx): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Clear what needs to be cleared after a use case execution
|
|
42
|
+
*
|
|
43
|
+
* For instance, this includes the data store, some fake queue processor checked in side effects, etc.
|
|
44
|
+
*
|
|
45
|
+
* @param ctx
|
|
46
|
+
*/
|
|
19
47
|
clearExecution(ctx: AppTesterCtx): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Define specific flows to test multiple use cases sequentially
|
|
50
|
+
*
|
|
51
|
+
* For example : SignUp > SignIn > SignOut > ResetPassword, etc.
|
|
52
|
+
*/
|
|
20
53
|
flows(): Promise<AppTesterFlow[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Define specific input fillers, per use case, in addition to the default ones
|
|
56
|
+
*
|
|
57
|
+
* @see defaultInputFillers
|
|
58
|
+
*/
|
|
21
59
|
inputFillers(): Promise<AppTesterConfiguratorInputFillers | undefined>;
|
|
60
|
+
/**
|
|
61
|
+
* Override the `ctx.opts()`, in case the app has some specificities
|
|
62
|
+
*/
|
|
22
63
|
opts(): Promise<AppTesterCtx['opts']>;
|
|
64
|
+
/**
|
|
65
|
+
* Seed some data in any data store needed by the use cases
|
|
66
|
+
*
|
|
67
|
+
* @param ctx
|
|
68
|
+
*/
|
|
23
69
|
seed(ctx: AppTesterCtx): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Register the side effects that need to be tracked
|
|
72
|
+
*
|
|
73
|
+
* For instance, this is where you register {@link FakeEmailManager.entries} to check the emails sent by use cases.
|
|
74
|
+
*
|
|
75
|
+
* Or it can also be the entries of some fake job processor to check the jobs dispatched by use cases.
|
|
76
|
+
*
|
|
77
|
+
* Note that it works only if there are no `specificAssertions` for the given use case.
|
|
78
|
+
*
|
|
79
|
+
* Otherwise, you need to assert side effects manually.
|
|
80
|
+
*
|
|
81
|
+
* @param ctx
|
|
82
|
+
*/
|
|
24
83
|
sideEffects(ctx: AppTesterCtx): Promise<AppTesterConfiguratorSideEffects | undefined>;
|
|
84
|
+
/**
|
|
85
|
+
* Define specific assertions for a specific use case
|
|
86
|
+
*
|
|
87
|
+
* Otherwise, it matches the snapshot.
|
|
88
|
+
*
|
|
89
|
+
* For instance, you can use this if a specific use case performs some random processing (e.g. generating random data).
|
|
90
|
+
*
|
|
91
|
+
* Generally speaking, it's always better to have deterministic tests, so it's usually better to bind deterministic implementations in the tests.
|
|
92
|
+
*/
|
|
25
93
|
specificAssertions(): Promise<AppTesterConfiguratorSpecificAssertions | undefined>;
|
|
26
94
|
}
|
|
@@ -3,6 +3,15 @@ import { type UCDataStore } from '../uc/index.js';
|
|
|
3
3
|
interface Input {
|
|
4
4
|
ucDataStore: UCDataStore;
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Test that a {@link UCDataStore} conforms to the spec
|
|
8
|
+
*
|
|
9
|
+
* By default it runs tests on the projection mechanism.
|
|
10
|
+
* Therefore, you need to create one in your implementation when creating your test suite.
|
|
11
|
+
* See `src/uc/impl/KnexUCDataStore.test.ts` for an example.
|
|
12
|
+
*
|
|
13
|
+
* Otherwise you can just `skipProjectionTesting`, although it's not recommended.
|
|
14
|
+
*/
|
|
6
15
|
export declare class UCDataStoreTester implements Worker<Input, Promise<void>> {
|
|
7
16
|
private clockManager;
|
|
8
17
|
private cryptoManager;
|
|
@@ -18,6 +18,15 @@ import { UCExecMode, } from '../uc/index.js';
|
|
|
18
18
|
const ERR_SHOULD_NOT_EXIST_AFTER_DESTROY = 'It should not exist after destroy';
|
|
19
19
|
const ERR_SHOULD_EXIST_AFTER_INSTALL = 'It should exist after install';
|
|
20
20
|
const ERR_SHOULD_RETURN_X_RECORDS = (n) => `It should return ${n} record(s)`;
|
|
21
|
+
/**
|
|
22
|
+
* Test that a {@link UCDataStore} conforms to the spec
|
|
23
|
+
*
|
|
24
|
+
* By default it runs tests on the projection mechanism.
|
|
25
|
+
* Therefore, you need to create one in your implementation when creating your test suite.
|
|
26
|
+
* See `src/uc/impl/KnexUCDataStore.test.ts` for an example.
|
|
27
|
+
*
|
|
28
|
+
* Otherwise you can just `skipProjectionTesting`, although it's not recommended.
|
|
29
|
+
*/
|
|
21
30
|
let UCDataStoreTester = class UCDataStoreTester {
|
|
22
31
|
static { UCDataStoreTester_1 = this; }
|
|
23
32
|
clockManager;
|
|
@@ -60,6 +69,7 @@ let UCDataStoreTester = class UCDataStoreTester {
|
|
|
60
69
|
await ucDataStore.clear();
|
|
61
70
|
this.readRes = await ucDataStore.read();
|
|
62
71
|
this.expectXRecords(0);
|
|
72
|
+
// Write a last one in case need to watch data in the DB
|
|
63
73
|
await this.ucDataStore.write({
|
|
64
74
|
aggregateId: this.cryptoManager.randomUUID(),
|
|
65
75
|
appName: APP_NAME_PLACEHOLDER,
|
|
@@ -116,9 +126,12 @@ let UCDataStoreTester = class UCDataStoreTester {
|
|
|
116
126
|
];
|
|
117
127
|
}
|
|
118
128
|
buildFiltersTestData() {
|
|
129
|
+
// biome-ignore lint/style/noNonNullAssertion: we're in a test
|
|
119
130
|
const entry = this.entries[0];
|
|
120
131
|
const [aggregateId, appName, ucNames, organizationId, userId] = entry;
|
|
132
|
+
// biome-ignore lint/style/noNonNullAssertion: we're in a test
|
|
121
133
|
const name = ucNames[0];
|
|
134
|
+
// TODO : Enhance these with a combination of filters
|
|
122
135
|
return [
|
|
123
136
|
[{ aggregateId }, 2],
|
|
124
137
|
[{ aggregateId: [aggregateId] }, 2],
|
|
@@ -33,6 +33,13 @@ SimpleAppDocsEmitter = __decorate([
|
|
|
33
33
|
__metadata("design:paramtypes", [Object])
|
|
34
34
|
], SimpleAppDocsEmitter);
|
|
35
35
|
export { SimpleAppDocsEmitter };
|
|
36
|
+
// For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
|
|
37
|
+
// Be aware that this will introduce complexities on building the lib.
|
|
38
|
+
// We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
|
|
39
|
+
// Hence the choice to keep it simple for now.
|
|
40
|
+
// Defined it as function in case we need to pass args.
|
|
41
|
+
// Using --- for the comment to make it compatible with pandoc
|
|
42
|
+
// See https://stackoverflow.com/a/4829998/1259118
|
|
36
43
|
const template = (cols, items) => `<!---
|
|
37
44
|
All this code has been auto generated.
|
|
38
45
|
DO NOT EDIT.
|
|
@@ -55,6 +62,9 @@ ${diagram(item)}`)
|
|
|
55
62
|
|---|${cols.map((_c) => '---').join('|')}|
|
|
56
63
|
${items.map((item, idx) => ['', idx + 1, ...cols.map((c) => fmtTechSummaryField(item[c])), ''].join('|')).join('\n')}
|
|
57
64
|
`;
|
|
65
|
+
/*
|
|
66
|
+
* Diagram
|
|
67
|
+
*/
|
|
58
68
|
const CHECK_POLICY = '🔐 Check policy';
|
|
59
69
|
const CHECK_POLICY_COND = 'when any validation fails';
|
|
60
70
|
const CHECK_POLICY_COND_ACTION = 'show failure';
|
|
@@ -69,6 +79,8 @@ const SEND = '📤 Send';
|
|
|
69
79
|
const SUBMIT = '↩️ Submit';
|
|
70
80
|
const TRIGGER = '⤴️ Trigger';
|
|
71
81
|
function diagram(item) {
|
|
82
|
+
// Debugger : https://mermaid.live/edit
|
|
83
|
+
// Messages : https://mermaid.js.org/syntax/sequenceDiagram.html#messages
|
|
72
84
|
const client = 'Client';
|
|
73
85
|
const server = 'Server';
|
|
74
86
|
const user = 'User';
|
|
@@ -76,6 +88,8 @@ function diagram(item) {
|
|
|
76
88
|
const { ioIFields, ioOPI0Fields, ioOPI1Fields, lifecycleClientPolicy, lifecycleClientSteps, lifecycleServerPolicy, lifecycleServerSteps, metadataSensitive, } = item;
|
|
77
89
|
let req = TRIGGER;
|
|
78
90
|
if (ioIFields && ioIFields.length > 0) {
|
|
91
|
+
// TODO : Include only fields to fill manually
|
|
92
|
+
// Not sure though, as for CLI for example (i.e. noContext), one needs to provide all of them
|
|
79
93
|
req = `${FILL}${LB}${diagramUCFields(item.ioIFields)}`;
|
|
80
94
|
}
|
|
81
95
|
lines.push(`${user}->>+${client}: ${req}`);
|
|
@@ -89,6 +103,7 @@ function diagram(item) {
|
|
|
89
103
|
if (lifecycleClientSteps) {
|
|
90
104
|
lines.push(...diagramUCMainSteps(client, lifecycleClientSteps));
|
|
91
105
|
}
|
|
106
|
+
// This is an approximation. Might need to improve it.
|
|
92
107
|
const hasServer = item.lifecycleServerPolicy?.value;
|
|
93
108
|
if (hasServer) {
|
|
94
109
|
req = SEND;
|
|
@@ -142,11 +157,16 @@ function diagramUCPolicy(participant, caller, lifecyclePolicyField) {
|
|
|
142
157
|
'end',
|
|
143
158
|
];
|
|
144
159
|
}
|
|
160
|
+
/*
|
|
161
|
+
* Technical Summary
|
|
162
|
+
*/
|
|
145
163
|
function fmtTechSummaryField(field) {
|
|
146
164
|
if (!field) {
|
|
147
165
|
return '';
|
|
148
166
|
}
|
|
149
167
|
const values = Array.isArray(field) ? field : [field];
|
|
168
|
+
// NOTE : <br> won't work for every markdown renderer.
|
|
169
|
+
// See https://stackoverflow.com/questions/11700487/how-do-i-add-a-newline-in-a-markdown-table
|
|
150
170
|
return values.map(fmtTechSummaryFieldVal).join('<br>');
|
|
151
171
|
}
|
|
152
172
|
function fmtTechSummaryFieldVal(field) {
|
|
@@ -155,7 +175,7 @@ function fmtTechSummaryFieldVal(field) {
|
|
|
155
175
|
if (err) {
|
|
156
176
|
res += `❌ ${err}`;
|
|
157
177
|
}
|
|
158
|
-
res = res.replace(/[\u00A0-\u9999<>\&]/g, (i) => `&#${i.charCodeAt(0)};`);
|
|
159
|
-
res = res.replaceAll('|', '\\|');
|
|
178
|
+
res = res.replace(/[\u00A0-\u9999<>\&]/g, (i) => `&#${i.charCodeAt(0)};`); // TS generics considered as HTML
|
|
179
|
+
res = res.replaceAll('|', '\\|'); // TS intersection vs Markdown table column
|
|
160
180
|
return res;
|
|
161
181
|
}
|
|
@@ -19,6 +19,7 @@ let SimpleHTMLAppTestReportEmitter = class SimpleHTMLAppTestReportEmitter {
|
|
|
19
19
|
}
|
|
20
20
|
async exec({ appPath, testResults, testSummary, }) {
|
|
21
21
|
const reportPath = this.reportPath(appPath);
|
|
22
|
+
// Since we're using 'recursive: true', there will be no error if the directory already exists
|
|
22
23
|
await this.fsManager.mkdir(reportPath, { recursive: true });
|
|
23
24
|
const tpl = template(appPath, testResults, testSummary);
|
|
24
25
|
const outPath = await this.entrypointPath(appPath);
|
|
@@ -43,6 +44,11 @@ SimpleHTMLAppTestReportEmitter = __decorate([
|
|
|
43
44
|
__metadata("design:paramtypes", [Object])
|
|
44
45
|
], SimpleHTMLAppTestReportEmitter);
|
|
45
46
|
export { SimpleHTMLAppTestReportEmitter };
|
|
47
|
+
// For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
|
|
48
|
+
// Be aware that this will introduce complexities on building the lib.
|
|
49
|
+
// We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
|
|
50
|
+
// Hence the choice to keep it simple for now.
|
|
51
|
+
// Defined it as function in case we need to pass args.
|
|
46
52
|
const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
|
|
47
53
|
<html lang="en">
|
|
48
54
|
<head>
|
|
@@ -142,9 +148,9 @@ const template = (appPath, testResults, testSummary) => `<!DOCTYPE html>
|
|
|
142
148
|
</html>
|
|
143
149
|
`;
|
|
144
150
|
const STATUS_COLOR_MAPPING = {
|
|
145
|
-
danger: '#ff4136',
|
|
146
|
-
success: '#42e6a4',
|
|
147
|
-
warning: '#ffff00',
|
|
151
|
+
danger: '#ff4136', // red
|
|
152
|
+
success: '#42e6a4', // green
|
|
153
|
+
warning: '#ffff00', // yellow
|
|
148
154
|
};
|
|
149
155
|
function statusStyles() {
|
|
150
156
|
return Object.entries(STATUS_COLOR_MAPPING)
|
|
@@ -12,6 +12,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { inject, injectable } from 'inversify';
|
|
14
14
|
import { isClassDeclaration, isObjectLiteralExpression, isPropertyAssignment, } from 'typescript';
|
|
15
|
+
// To avoid the following error when used in a consumer :
|
|
16
|
+
// SyntaxError: Named export 'ModuleKind' not found. The requested module 'typescript' is a CommonJS module, which may not support all module.exports as named exports.
|
|
17
|
+
// CommonJS modules can always be imported via the default export
|
|
15
18
|
import typescript from 'typescript';
|
|
16
19
|
const { ModuleKind, ModuleResolutionKind, ScriptTarget, createProgram, flattenDiagnosticMessageText, forEachChild, getPreEmitDiagnostics, isIdentifier, isImportDeclaration, isPropertySignature, isStringLiteral, isTypeReferenceNode, isVariableStatement, } = typescript;
|
|
17
20
|
import { UC_MAIN_CLIENT_SUFFIX, UC_MAIN_SERVER_SUFFIX, UC_MAIN_STEP_PREFIX_REGULAR, UC_MAIN_SUFFIX, UC_POLICY_SUFFIX, } from '../../convention.js';
|
|
@@ -89,8 +92,10 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
89
92
|
target: ScriptTarget[(compilerOptionsBase.target ??
|
|
90
93
|
target)],
|
|
91
94
|
};
|
|
92
|
-
|
|
93
|
-
this.compilerOptions.
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
this.compilerOptions.jsx = undefined; // Otherwise it triggers the following error since TS 5.5 : jsx is a string value; tsconfig JSON must be parsed with parseJsonSourceFileConfigFileContent or getParsedCommandLineOfConfigFile before passing to createProgram
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
this.compilerOptions.lib = undefined; // Otherwise it triggers errors saying it does not find them
|
|
94
99
|
}
|
|
95
100
|
getTypeFields(node) {
|
|
96
101
|
const type = this.typeChecker.getTypeAtLocation(node);
|
|
@@ -114,9 +119,12 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
114
119
|
return fields;
|
|
115
120
|
}
|
|
116
121
|
processConstDeclaration(node, onMainStep, onPolicy, onMetadata) {
|
|
122
|
+
// TODO : Improve this whole pattern by making it more robust
|
|
123
|
+
// I think there is a risk of it to break in some cases (e.g. if there are other properties named main, policy, etc.)
|
|
117
124
|
const metadataPropertyName = 'metadata';
|
|
118
125
|
const nodes = [];
|
|
119
126
|
const populateNodes = (node1) => {
|
|
127
|
+
// "main: SendClientMain" => "main", ":", "SendClientMain" => 3
|
|
120
128
|
if (isPropertyAssignment(node1) && node1.getChildCount() === 3) {
|
|
121
129
|
const propertyName = node1.getChildAt(0).getText();
|
|
122
130
|
if (propertyName === UC_MAIN_SUFFIX.toLocaleLowerCase() ||
|
|
@@ -137,7 +145,7 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
137
145
|
this.processLifecycleMain('server', node1, onMainStep);
|
|
138
146
|
}
|
|
139
147
|
else if (text.endsWith(UC_POLICY_SUFFIX)) {
|
|
140
|
-
const parent = node1.parent.getText();
|
|
148
|
+
const parent = node1.parent.getText(); // { main: X(Client|Server)Main, policy: XUCPolicy }
|
|
141
149
|
if (parent.includes(UC_MAIN_CLIENT_SUFFIX)) {
|
|
142
150
|
this.processLifecyclePolicy('client', node1, onPolicy);
|
|
143
151
|
}
|
|
@@ -211,7 +219,7 @@ let TypeScriptLibUCDefASTParser = class TypeScriptLibUCDefASTParser {
|
|
|
211
219
|
value = Boolean(value);
|
|
212
220
|
}
|
|
213
221
|
else {
|
|
214
|
-
value = value.substring(1, v.length - 1);
|
|
222
|
+
value = value.substring(1, v.length - 1); // To remove the single quotes
|
|
215
223
|
}
|
|
216
224
|
metadataLike[k] = value;
|
|
217
225
|
}
|
|
@@ -19,6 +19,7 @@ let VitestAppTestSuiteEmitter = class VitestAppTestSuiteEmitter {
|
|
|
19
19
|
}
|
|
20
20
|
async exec({ appPath, depsMapping, idx, monkeyTestingTimeoutInMs, serverPortRangeStart, }) {
|
|
21
21
|
const testPath = this.fsManager.path(appPath, APP_TEST_DIR_NAME);
|
|
22
|
+
// Since we're using 'recursive: true', there will be no error if the directory already exists
|
|
22
23
|
await this.fsManager.mkdir(testPath, { recursive: true });
|
|
23
24
|
const outPath = this.fsManager.path(testPath, APP_TEST_MAIN_FILE_NAME);
|
|
24
25
|
let tpl = template(serverPortRangeStart, idx, monkeyTestingTimeoutInMs);
|
|
@@ -37,6 +38,11 @@ VitestAppTestSuiteEmitter = __decorate([
|
|
|
37
38
|
__metadata("design:paramtypes", [Object])
|
|
38
39
|
], VitestAppTestSuiteEmitter);
|
|
39
40
|
export { VitestAppTestSuiteEmitter };
|
|
41
|
+
// For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
|
|
42
|
+
// Be aware that this will introduce complexities on building the lib.
|
|
43
|
+
// We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
|
|
44
|
+
// Hence the choice to keep it simple for now.
|
|
45
|
+
// Defined it as function in case we need to pass args.
|
|
40
46
|
const template = (serverPortRangeStart, idx, monkeyTestingTimeoutInMs) => `/*
|
|
41
47
|
All this code has been auto generated.
|
|
42
48
|
DO NOT EDIT.
|
|
@@ -5,25 +5,63 @@ import type { AppTesterCtx } from './ctx.js';
|
|
|
5
5
|
type AppTesterOptsAliasPrefix = string;
|
|
6
6
|
type AppTesterOptsImportsList = string[];
|
|
7
7
|
export interface AppTesterTypeScriptOpts {
|
|
8
|
+
/**
|
|
9
|
+
* Although the TS lib relies on an enum (`ModuleKind`), we use plain text so it's compatible with a regular tsconfig.json
|
|
10
|
+
* @see https://www.typescriptlang.org/tsconfig/#module
|
|
11
|
+
* @defaultValue "NodeNext"
|
|
12
|
+
*/
|
|
8
13
|
module?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Although the TS lib relies on an enum (`ModuleResolutionKind`), we use plain text so it's compatible with a regular tsconfig.json
|
|
16
|
+
* @see https://www.typescriptlang.org/tsconfig/#moduleResolution
|
|
17
|
+
* @defaultValue "NodeNext"
|
|
18
|
+
*/
|
|
9
19
|
moduleResolution?: string;
|
|
20
|
+
/**
|
|
21
|
+
* @see https://www.typescriptlang.org/tsconfig/#noCheck
|
|
22
|
+
* @defaultValue true
|
|
23
|
+
*/
|
|
10
24
|
noCheck?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* @see https://www.typescriptlang.org/tsconfig/#skipLibCheck
|
|
27
|
+
* @defaultValue true
|
|
28
|
+
*/
|
|
11
29
|
skipLibCheck?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Although the TS lib relies on an enum (`ScriptTarget`), we use plain text so it's compatible with a regular tsconfig.json
|
|
32
|
+
* @see https://www.typescriptlang.org/tsconfig/#target
|
|
33
|
+
* @defaultValue "ESNext"
|
|
34
|
+
*/
|
|
12
35
|
target?: string;
|
|
13
36
|
}
|
|
14
37
|
export type AppTesterOpts = Partial<Pick<LoggerSettings, 'logger_level'>> & {
|
|
15
38
|
source?: {
|
|
16
39
|
imports?: {
|
|
17
40
|
external?: {
|
|
41
|
+
/**
|
|
42
|
+
* @defaultValue '@'
|
|
43
|
+
*/
|
|
18
44
|
aliasPrefix?: AppTesterOptsAliasPrefix;
|
|
45
|
+
/**
|
|
46
|
+
* @defaultValue ['fik-sdk', 'inversify']
|
|
47
|
+
*/
|
|
19
48
|
allowed?: AppTesterOptsImportsList;
|
|
20
49
|
};
|
|
21
50
|
internal?: {
|
|
51
|
+
/**
|
|
52
|
+
* @defaultValue '../../'
|
|
53
|
+
*/
|
|
22
54
|
maxDepth?: FilePath;
|
|
55
|
+
/**
|
|
56
|
+
* @defaultValue '.'
|
|
57
|
+
*/
|
|
23
58
|
startChar?: string;
|
|
24
59
|
};
|
|
25
60
|
};
|
|
26
61
|
ts?: {
|
|
62
|
+
/**
|
|
63
|
+
* @defaultValue tsconfig.json
|
|
64
|
+
*/
|
|
27
65
|
configFileName?: FileName;
|
|
28
66
|
} & AppTesterTypeScriptOpts;
|
|
29
67
|
};
|
package/dist/esm/testing/opts.js
CHANGED
|
@@ -33,11 +33,13 @@ export function onlySetProgrammaticallyWithExamples(uc) {
|
|
|
33
33
|
fillWithExample(f);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
36
37
|
function fillWithExample(f) {
|
|
37
38
|
const { type } = f.def;
|
|
38
39
|
let val = type.getExamples()?.[0] ?? type.example();
|
|
39
40
|
if (type instanceof TFile) {
|
|
40
41
|
const file = val;
|
|
42
|
+
// TODO : Consider building a real file with real data (e.g. image, pdf, txt, etc.)
|
|
41
43
|
val = new File(['01010101010101010101010101010101'], file.path, {
|
|
42
44
|
type: file.type,
|
|
43
45
|
});
|