@nocobase/plugin-flow-engine 2.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +29 -0
- package/build.config.ts +22 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/index.d.ts +15 -0
- package/dist/client/index.js +10 -0
- package/dist/externalVersion.js +21 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +48 -0
- package/dist/locale/en-US.json +61 -0
- package/dist/locale/index.d.ts +141 -0
- package/dist/locale/index.js +79 -0
- package/dist/locale/zh-CN.json +61 -0
- package/dist/node_modules/ses/LICENSE +201 -0
- package/dist/node_modules/ses/LICENSE-aura +16 -0
- package/dist/node_modules/ses/LICENSE-caja +13 -0
- package/dist/node_modules/ses/LICENSE-corejs +19 -0
- package/dist/node_modules/ses/LICENSE-v8 +9 -0
- package/dist/node_modules/ses/assert-shim.js +1 -0
- package/dist/node_modules/ses/compartment-shim.js +1 -0
- package/dist/node_modules/ses/console-shim.js +1 -0
- package/dist/node_modules/ses/dist/lockdown.cjs +13912 -0
- package/dist/node_modules/ses/dist/lockdown.umd.js +13912 -0
- package/dist/node_modules/ses/dist/lockdown.umd.min.js +1 -0
- package/dist/node_modules/ses/dist/ses-hermes.cjs +13912 -0
- package/dist/node_modules/ses/dist/ses.cjs +1 -0
- package/dist/node_modules/ses/dist/ses.umd.js +13912 -0
- package/dist/node_modules/ses/dist/ses.umd.min.js +1 -0
- package/dist/node_modules/ses/dist/types.d.cts +606 -0
- package/dist/node_modules/ses/index.js +18 -0
- package/dist/node_modules/ses/lockdown-shim.js +1 -0
- package/dist/node_modules/ses/lockdown.js +1 -0
- package/dist/node_modules/ses/package.json +1 -0
- package/dist/node_modules/ses/src/assert-shim.js +4 -0
- package/dist/node_modules/ses/src/assert-sloppy-mode.js +11 -0
- package/dist/node_modules/ses/src/cauterize-property.js +69 -0
- package/dist/node_modules/ses/src/commons.js +425 -0
- package/dist/node_modules/ses/src/compartment-evaluate.js +93 -0
- package/dist/node_modules/ses/src/compartment-shim.js +22 -0
- package/dist/node_modules/ses/src/compartment.js +477 -0
- package/dist/node_modules/ses/src/console-shim.js +50 -0
- package/dist/node_modules/ses/src/enable-property-overrides.js +211 -0
- package/dist/node_modules/ses/src/enablements.js +244 -0
- package/dist/node_modules/ses/src/error/assert.js +584 -0
- package/dist/node_modules/ses/src/error/console.js +541 -0
- package/dist/node_modules/ses/src/error/fatal-assert.js +54 -0
- package/dist/node_modules/ses/src/error/internal-types.js +98 -0
- package/dist/node_modules/ses/src/error/note-log-args.js +77 -0
- package/dist/node_modules/ses/src/error/stringify-utils.js +195 -0
- package/dist/node_modules/ses/src/error/tame-console.js +197 -0
- package/dist/node_modules/ses/src/error/tame-error-constructor.js +284 -0
- package/dist/node_modules/ses/src/error/tame-v8-error-constructor.js +386 -0
- package/dist/node_modules/ses/src/error/types.js +59 -0
- package/dist/node_modules/ses/src/error/unhandled-rejection.js +122 -0
- package/dist/node_modules/ses/src/eval-scope.js +89 -0
- package/dist/node_modules/ses/src/get-anonymous-intrinsics.js +181 -0
- package/dist/node_modules/ses/src/get-source-url.js +50 -0
- package/dist/node_modules/ses/src/global-object.js +175 -0
- package/dist/node_modules/ses/src/intrinsics.js +192 -0
- package/dist/node_modules/ses/src/lockdown-shim.js +37 -0
- package/dist/node_modules/ses/src/lockdown.js +558 -0
- package/dist/node_modules/ses/src/make-eval-function.js +28 -0
- package/dist/node_modules/ses/src/make-evaluate.js +110 -0
- package/dist/node_modules/ses/src/make-function-constructor.js +79 -0
- package/dist/node_modules/ses/src/make-hardener.js +275 -0
- package/dist/node_modules/ses/src/make-safe-evaluator.js +112 -0
- package/dist/node_modules/ses/src/module-instance.js +497 -0
- package/dist/node_modules/ses/src/module-link.js +159 -0
- package/dist/node_modules/ses/src/module-load.js +719 -0
- package/dist/node_modules/ses/src/module-proxy.js +200 -0
- package/dist/node_modules/ses/src/permits-intrinsics.js +291 -0
- package/dist/node_modules/ses/src/permits.js +1761 -0
- package/dist/node_modules/ses/src/reporting-types.d.ts +13 -0
- package/dist/node_modules/ses/src/reporting.js +105 -0
- package/dist/node_modules/ses/src/scope-constants.js +180 -0
- package/dist/node_modules/ses/src/shim-arraybuffer-transfer.js +85 -0
- package/dist/node_modules/ses/src/sloppy-globals-scope-terminator.js +61 -0
- package/dist/node_modules/ses/src/strict-scope-terminator.js +99 -0
- package/dist/node_modules/ses/src/tame-date-constructor.js +127 -0
- package/dist/node_modules/ses/src/tame-domains.js +41 -0
- package/dist/node_modules/ses/src/tame-faux-data-properties.js +210 -0
- package/dist/node_modules/ses/src/tame-function-constructors.js +140 -0
- package/dist/node_modules/ses/src/tame-function-tostring.js +50 -0
- package/dist/node_modules/ses/src/tame-harden.js +29 -0
- package/dist/node_modules/ses/src/tame-locale-methods.js +78 -0
- package/dist/node_modules/ses/src/tame-math-object.js +41 -0
- package/dist/node_modules/ses/src/tame-module-source.js +51 -0
- package/dist/node_modules/ses/src/tame-regenerator-runtime.js +29 -0
- package/dist/node_modules/ses/src/tame-regexp-constructor.js +65 -0
- package/dist/node_modules/ses/src/tame-symbol-constructor.js +64 -0
- package/dist/node_modules/ses/src/transforms.js +267 -0
- package/dist/node_modules/ses/tools.js +25 -0
- package/dist/node_modules/ses/types.d.ts +606 -0
- package/dist/server/actions/ui-schema-action.d.ts +27 -0
- package/dist/server/actions/ui-schema-action.js +118 -0
- package/dist/server/collections/flowModelTreePath.d.ts +11 -0
- package/dist/server/collections/flowModelTreePath.js +74 -0
- package/dist/server/collections/flowModels.d.ts +11 -0
- package/dist/server/collections/flowModels.js +57 -0
- package/dist/server/collections/flowsql.d.ts +10 -0
- package/dist/server/collections/flowsql.js +51 -0
- package/dist/server/dao/ui_schema_node_dao.d.ts +26 -0
- package/dist/server/dao/ui_schema_node_dao.js +24 -0
- package/dist/server/helper.d.ts +8 -0
- package/dist/server/helper.js +9 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.js +42 -0
- package/dist/server/model.d.ts +12 -0
- package/dist/server/model.js +38 -0
- package/dist/server/plugin.d.ts +26 -0
- package/dist/server/plugin.js +270 -0
- package/dist/server/repository.d.ts +116 -0
- package/dist/server/repository.js +1209 -0
- package/dist/server/server.d.ts +16 -0
- package/dist/server/server.js +198 -0
- package/dist/server/template/contexts.d.ts +73 -0
- package/dist/server/template/contexts.js +233 -0
- package/dist/server/template/resolver.d.ts +30 -0
- package/dist/server/template/resolver.js +225 -0
- package/dist/server/variables/registry.d.ts +42 -0
- package/dist/server/variables/registry.js +299 -0
- package/package.json +28 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
// To ensure that this module operates without special privilege, it should
|
|
4
|
+
// not reference the free variable `console` except for its own internal
|
|
5
|
+
// debugging purposes in the declaration of `internalDebugConsole`, which is
|
|
6
|
+
// normally commented out.
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
WeakSet,
|
|
10
|
+
arrayFilter,
|
|
11
|
+
arrayFlatMap,
|
|
12
|
+
arrayMap,
|
|
13
|
+
arrayPop,
|
|
14
|
+
arrayPush,
|
|
15
|
+
defineProperty,
|
|
16
|
+
freeze,
|
|
17
|
+
fromEntries,
|
|
18
|
+
isError,
|
|
19
|
+
stringEndsWith,
|
|
20
|
+
stringIncludes,
|
|
21
|
+
stringSplit,
|
|
22
|
+
weaksetAdd,
|
|
23
|
+
weaksetHas,
|
|
24
|
+
} from '../commons.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @import {FilterConsole, LogSeverity, VirtualConsole} from './types.js'
|
|
28
|
+
* @import {ErrorInfo, ErrorInfoKind, LogRecord, NoteCallback, LoggedErrorHandler, MakeCausalConsole, MakeLoggingConsoleKit} from "./internal-types.js";
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Explicitly set a function's name, supporting use of arrow functions for which
|
|
33
|
+
* source text doesn't include a name and no initial name is set by
|
|
34
|
+
* NamedEvaluation
|
|
35
|
+
* https://tc39.es/ecma262/multipage/syntax-directed-operations.html#sec-runtime-semantics-namedevaluation
|
|
36
|
+
* Instead, we hope that tooling uses only the explicit `name` property.
|
|
37
|
+
*
|
|
38
|
+
* @template {Function} F
|
|
39
|
+
* @param {string} name
|
|
40
|
+
* @param {F} fn
|
|
41
|
+
* @returns {F}
|
|
42
|
+
*/
|
|
43
|
+
const defineName = (name, fn) => defineProperty(fn, 'name', { value: name });
|
|
44
|
+
|
|
45
|
+
// For our internal debugging purposes, uncomment
|
|
46
|
+
// const internalDebugConsole = console;
|
|
47
|
+
|
|
48
|
+
// The permitted console methods, from:
|
|
49
|
+
// Whatwg "living standard" https://console.spec.whatwg.org/
|
|
50
|
+
// Node https://nodejs.org/dist/latest-v14.x/docs/api/console.html
|
|
51
|
+
// MDN https://developer.mozilla.org/en-US/docs/Web/API/Console_API
|
|
52
|
+
// TypeScript https://openstapps.gitlab.io/projectmanagement/interfaces/_node_modules__types_node_globals_d_.console.html
|
|
53
|
+
// Chrome https://developers.google.com/web/tools/chrome-devtools/console/api
|
|
54
|
+
|
|
55
|
+
// All console level methods have parameters (fmt?, ...args)
|
|
56
|
+
// where the argument sequence `fmt?, ...args` formats args according to
|
|
57
|
+
// fmt if fmt is a format string. Otherwise, it just renders them all as values
|
|
58
|
+
// separated by spaces.
|
|
59
|
+
// https://console.spec.whatwg.org/#formatter
|
|
60
|
+
// https://nodejs.org/docs/latest/api/util.html#util_util_format_format_args
|
|
61
|
+
|
|
62
|
+
// For the causal console, all occurrences of `fmt, ...args` or `...args` by
|
|
63
|
+
// itself must check for the presence of an error to ask the
|
|
64
|
+
// `loggedErrorHandler` to handle.
|
|
65
|
+
// In theory we should do a deep inspection to detect for example an array
|
|
66
|
+
// containing an error. We currently do not detect these and may never.
|
|
67
|
+
|
|
68
|
+
/** @typedef {keyof VirtualConsole | 'profile' | 'profileEnd'} ConsoleProps */
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Those console methods whose actual parameters are `(fmt?, ...args)`
|
|
72
|
+
* even if their TypeScript types claim otherwise.
|
|
73
|
+
*
|
|
74
|
+
* Each is paired with what we consider to be their log severity level.
|
|
75
|
+
* This is the same as the log severity of these on other
|
|
76
|
+
* platform console implementations when they all agree.
|
|
77
|
+
*
|
|
78
|
+
* @type {readonly [ConsoleProps, LogSeverity | undefined][]}
|
|
79
|
+
*/
|
|
80
|
+
export const consoleLevelMethods = freeze([
|
|
81
|
+
['debug', 'debug'], // (fmt?, ...args) verbose level on Chrome
|
|
82
|
+
['log', 'log'], // (fmt?, ...args) info level on Chrome
|
|
83
|
+
['info', 'info'], // (fmt?, ...args)
|
|
84
|
+
['warn', 'warn'], // (fmt?, ...args)
|
|
85
|
+
['error', 'error'], // (fmt?, ...args)
|
|
86
|
+
|
|
87
|
+
['trace', 'log'], // (fmt?, ...args)
|
|
88
|
+
['dirxml', 'log'], // (fmt?, ...args) but TS typed (...data)
|
|
89
|
+
['group', 'log'], // (fmt?, ...args) but TS typed (...label)
|
|
90
|
+
['groupCollapsed', 'log'], // (fmt?, ...args) but TS typed (...label)
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Those console methods other than those already enumerated by
|
|
95
|
+
* `consoleLevelMethods`.
|
|
96
|
+
*
|
|
97
|
+
* Each is paired with what we consider to be their log severity level.
|
|
98
|
+
* This is the same as the log severity of these on other
|
|
99
|
+
* platform console implementations when they all agree.
|
|
100
|
+
*
|
|
101
|
+
* @type {readonly [ConsoleProps, LogSeverity | undefined][]}
|
|
102
|
+
*/
|
|
103
|
+
export const consoleOtherMethods = freeze([
|
|
104
|
+
['assert', 'error'], // (value, fmt?, ...args)
|
|
105
|
+
['timeLog', 'log'], // (label?, ...args) no fmt string
|
|
106
|
+
|
|
107
|
+
// Insensitive to whether any argument is an error. All arguments can pass
|
|
108
|
+
// thru to baseConsole as is.
|
|
109
|
+
['clear', undefined], // ()
|
|
110
|
+
['count', 'info'], // (label?)
|
|
111
|
+
['countReset', undefined], // (label?)
|
|
112
|
+
['dir', 'log'], // (item, options?)
|
|
113
|
+
['groupEnd', 'log'], // ()
|
|
114
|
+
// In theory tabular data may be or contain an error. However, we currently
|
|
115
|
+
// do not detect these and may never.
|
|
116
|
+
['table', 'log'], // (tabularData, properties?)
|
|
117
|
+
['time', 'info'], // (label?)
|
|
118
|
+
['timeEnd', 'info'], // (label?)
|
|
119
|
+
|
|
120
|
+
// Node Inspector only, MDN, and TypeScript, but not whatwg
|
|
121
|
+
['profile', undefined], // (label?)
|
|
122
|
+
['profileEnd', undefined], // (label?)
|
|
123
|
+
['timeStamp', undefined], // (label?)
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
/** @type {readonly [ConsoleProps, LogSeverity | undefined][]} */
|
|
127
|
+
const consoleMethodPermits = freeze([
|
|
128
|
+
...consoleLevelMethods,
|
|
129
|
+
...consoleOtherMethods,
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* consoleOmittedProperties is currently unused. I record and maintain it here
|
|
134
|
+
* with the intention that it be treated like the `false` entries in the main
|
|
135
|
+
* SES permits: that seeing these on the original console is expected, but
|
|
136
|
+
* seeing anything else that's outside the permits is surprising and should
|
|
137
|
+
* provide a diagnostic.
|
|
138
|
+
*
|
|
139
|
+
* const consoleOmittedProperties = freeze([
|
|
140
|
+
* 'memory', // Chrome
|
|
141
|
+
* 'exception', // FF, MDN
|
|
142
|
+
* '_ignoreErrors', // Node
|
|
143
|
+
* '_stderr', // Node
|
|
144
|
+
* '_stderrErrorHandler', // Node
|
|
145
|
+
* '_stdout', // Node
|
|
146
|
+
* '_stdoutErrorHandler', // Node
|
|
147
|
+
* '_times', // Node
|
|
148
|
+
* 'context', // Chrome, Node
|
|
149
|
+
* 'record', // Safari
|
|
150
|
+
* 'recordEnd', // Safari
|
|
151
|
+
*
|
|
152
|
+
* 'screenshot', // Safari
|
|
153
|
+
* // Symbols
|
|
154
|
+
* '@@toStringTag', // Chrome: "Object", Safari: "Console"
|
|
155
|
+
* // A variety of other symbols also seen on Node
|
|
156
|
+
* ]);
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
// //////////////////////////// Logging Console ////////////////////////////////
|
|
160
|
+
|
|
161
|
+
/** @type {MakeLoggingConsoleKit} */
|
|
162
|
+
export const makeLoggingConsoleKit = (
|
|
163
|
+
loggedErrorHandler,
|
|
164
|
+
{ shouldResetForDebugging = false } = {},
|
|
165
|
+
) => {
|
|
166
|
+
if (shouldResetForDebugging) {
|
|
167
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
168
|
+
loggedErrorHandler.resetErrorTagNum();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Not frozen!
|
|
172
|
+
let logArray = [];
|
|
173
|
+
|
|
174
|
+
const loggingConsole = fromEntries(
|
|
175
|
+
arrayMap(consoleMethodPermits, ([name, _]) => {
|
|
176
|
+
/**
|
|
177
|
+
* @param {...any} args
|
|
178
|
+
*/
|
|
179
|
+
const method = defineName(name, (...args) => {
|
|
180
|
+
arrayPush(logArray, [name, ...args]);
|
|
181
|
+
});
|
|
182
|
+
return [name, freeze(method)];
|
|
183
|
+
}),
|
|
184
|
+
);
|
|
185
|
+
freeze(loggingConsole);
|
|
186
|
+
|
|
187
|
+
const takeLog = () => {
|
|
188
|
+
const result = freeze(logArray);
|
|
189
|
+
logArray = [];
|
|
190
|
+
return result;
|
|
191
|
+
};
|
|
192
|
+
freeze(takeLog);
|
|
193
|
+
|
|
194
|
+
const typedLoggingConsole = /** @type {VirtualConsole} */ (loggingConsole);
|
|
195
|
+
|
|
196
|
+
return freeze({ loggingConsole: typedLoggingConsole, takeLog });
|
|
197
|
+
};
|
|
198
|
+
freeze(makeLoggingConsoleKit);
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Makes the same calls on a `baseConsole` that were made on a
|
|
202
|
+
* `loggingConsole` to produce this `log`. In this way, a logging console
|
|
203
|
+
* can be used as a buffer to delay the application of these calls to a
|
|
204
|
+
* `baseConsole`.
|
|
205
|
+
*
|
|
206
|
+
* @param {LogRecord[]} log
|
|
207
|
+
* @param {VirtualConsole} baseConsole
|
|
208
|
+
*/
|
|
209
|
+
export const pumpLogToConsole = (log, baseConsole) => {
|
|
210
|
+
for (const [name, ...args] of log) {
|
|
211
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
212
|
+
baseConsole[name](...args);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
// //////////////////////////// Causal Console /////////////////////////////////
|
|
216
|
+
|
|
217
|
+
/** @type {ErrorInfo} */
|
|
218
|
+
const ErrorInfo = {
|
|
219
|
+
NOTE: 'ERROR_NOTE:',
|
|
220
|
+
MESSAGE: 'ERROR_MESSAGE:',
|
|
221
|
+
CAUSE: 'cause:',
|
|
222
|
+
ERRORS: 'errors:',
|
|
223
|
+
};
|
|
224
|
+
freeze(ErrorInfo);
|
|
225
|
+
|
|
226
|
+
/** @type {MakeCausalConsole} */
|
|
227
|
+
export const makeCausalConsole = (baseConsole, loggedErrorHandler) => {
|
|
228
|
+
if (!baseConsole) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const { getStackString, tagError, takeMessageLogArgs, takeNoteLogArgsArray } =
|
|
233
|
+
loggedErrorHandler;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @param {ReadonlyArray<any>} logArgs
|
|
237
|
+
* @param {Array<any>} subErrorsSink
|
|
238
|
+
* @returns {any}
|
|
239
|
+
*/
|
|
240
|
+
const extractErrorArgs = (logArgs, subErrorsSink) => {
|
|
241
|
+
const argTags = arrayMap(logArgs, arg => {
|
|
242
|
+
if (isError(arg)) {
|
|
243
|
+
arrayPush(subErrorsSink, arg);
|
|
244
|
+
return `(${tagError(arg)})`;
|
|
245
|
+
}
|
|
246
|
+
return arg;
|
|
247
|
+
});
|
|
248
|
+
return argTags;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @param {LogSeverity} severity
|
|
253
|
+
* @param {Error} error
|
|
254
|
+
* @param {ErrorInfoKind} kind
|
|
255
|
+
* @param {readonly any[]} logArgs
|
|
256
|
+
* @param {Array<Error>} subErrorsSink
|
|
257
|
+
*/
|
|
258
|
+
const logErrorInfo = (severity, error, kind, logArgs, subErrorsSink) => {
|
|
259
|
+
const errorTag = tagError(error);
|
|
260
|
+
const errorName =
|
|
261
|
+
kind === ErrorInfo.MESSAGE ? `${errorTag}:` : `${errorTag} ${kind}`;
|
|
262
|
+
const argTags = extractErrorArgs(logArgs, subErrorsSink);
|
|
263
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
264
|
+
baseConsole[severity](errorName, ...argTags);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Logs the `subErrors` within a group name mentioning `optTag`.
|
|
269
|
+
*
|
|
270
|
+
* @param {LogSeverity} severity
|
|
271
|
+
* @param {Error[]} subErrors
|
|
272
|
+
* @param {string | undefined} optTag
|
|
273
|
+
* @returns {void}
|
|
274
|
+
*/
|
|
275
|
+
const logSubErrors = (severity, subErrors, optTag = undefined) => {
|
|
276
|
+
if (subErrors.length === 0) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (subErrors.length === 1 && optTag === undefined) {
|
|
280
|
+
// eslint-disable-next-line no-use-before-define
|
|
281
|
+
logError(severity, subErrors[0]);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
let label;
|
|
285
|
+
if (subErrors.length === 1) {
|
|
286
|
+
label = `Nested error`;
|
|
287
|
+
} else {
|
|
288
|
+
label = `Nested ${subErrors.length} errors`;
|
|
289
|
+
}
|
|
290
|
+
if (optTag !== undefined) {
|
|
291
|
+
label = `${label} under ${optTag}`;
|
|
292
|
+
}
|
|
293
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
294
|
+
baseConsole.group(label);
|
|
295
|
+
try {
|
|
296
|
+
for (const subError of subErrors) {
|
|
297
|
+
// eslint-disable-next-line no-use-before-define
|
|
298
|
+
logError(severity, subError);
|
|
299
|
+
}
|
|
300
|
+
} finally {
|
|
301
|
+
if (baseConsole.groupEnd) {
|
|
302
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
303
|
+
baseConsole.groupEnd();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const errorsLogged = new WeakSet();
|
|
309
|
+
|
|
310
|
+
/** @type {(severity: LogSeverity) => NoteCallback} */
|
|
311
|
+
const makeNoteCallback = severity => (error, noteLogArgs) => {
|
|
312
|
+
const subErrors = [];
|
|
313
|
+
// Annotation arrived after the error has already been logged,
|
|
314
|
+
// so just log the annotation immediately, rather than remembering it.
|
|
315
|
+
logErrorInfo(severity, error, ErrorInfo.NOTE, noteLogArgs, subErrors);
|
|
316
|
+
logSubErrors(severity, subErrors, tagError(error));
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @param {LogSeverity} severity
|
|
321
|
+
* @param {Error} error
|
|
322
|
+
*/
|
|
323
|
+
const logError = (severity, error) => {
|
|
324
|
+
if (weaksetHas(errorsLogged, error)) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const errorTag = tagError(error);
|
|
328
|
+
weaksetAdd(errorsLogged, error);
|
|
329
|
+
const subErrors = [];
|
|
330
|
+
const messageLogArgs = takeMessageLogArgs(error);
|
|
331
|
+
const noteLogArgsArray = takeNoteLogArgsArray(
|
|
332
|
+
error,
|
|
333
|
+
makeNoteCallback(severity),
|
|
334
|
+
);
|
|
335
|
+
// Show the error's most informative error message
|
|
336
|
+
if (messageLogArgs === undefined) {
|
|
337
|
+
// If there is no message log args, then just show the message that
|
|
338
|
+
// the error itself carries.
|
|
339
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
340
|
+
baseConsole[severity](`${errorTag}:`, error.message);
|
|
341
|
+
} else {
|
|
342
|
+
// If there is one, we take it to be strictly more informative than the
|
|
343
|
+
// message string carried by the error, so show it *instead*.
|
|
344
|
+
logErrorInfo(
|
|
345
|
+
severity,
|
|
346
|
+
error,
|
|
347
|
+
ErrorInfo.MESSAGE,
|
|
348
|
+
messageLogArgs,
|
|
349
|
+
subErrors,
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
// After the message but before any other annotations, show the stack.
|
|
353
|
+
let stackString = getStackString(error);
|
|
354
|
+
if (
|
|
355
|
+
typeof stackString === 'string' &&
|
|
356
|
+
stackString.length >= 1 &&
|
|
357
|
+
!stringEndsWith(stackString, '\n')
|
|
358
|
+
) {
|
|
359
|
+
stackString += '\n';
|
|
360
|
+
}
|
|
361
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
362
|
+
baseConsole[severity](stackString);
|
|
363
|
+
// Show the other annotations on error
|
|
364
|
+
if (error.cause) {
|
|
365
|
+
logErrorInfo(severity, error, ErrorInfo.CAUSE, [error.cause], subErrors);
|
|
366
|
+
}
|
|
367
|
+
// @ts-expect-error AggregateError has an `errors` property.
|
|
368
|
+
if (error.errors) {
|
|
369
|
+
// @ts-expect-error AggregateError has an `errors` property.
|
|
370
|
+
logErrorInfo(severity, error, ErrorInfo.ERRORS, error.errors, subErrors);
|
|
371
|
+
}
|
|
372
|
+
for (const noteLogArgs of noteLogArgsArray) {
|
|
373
|
+
logErrorInfo(severity, error, ErrorInfo.NOTE, noteLogArgs, subErrors);
|
|
374
|
+
}
|
|
375
|
+
// explain all the errors seen in the messages already emitted.
|
|
376
|
+
logSubErrors(severity, subErrors, errorTag);
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const levelMethods = arrayMap(consoleLevelMethods, ([level, _]) => {
|
|
380
|
+
/**
|
|
381
|
+
* @param {...any} logArgs
|
|
382
|
+
*/
|
|
383
|
+
const levelMethod = defineName(level, (...logArgs) => {
|
|
384
|
+
const subErrors = [];
|
|
385
|
+
const argTags = extractErrorArgs(logArgs, subErrors);
|
|
386
|
+
if (baseConsole[level]) {
|
|
387
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
388
|
+
baseConsole[level](...argTags);
|
|
389
|
+
}
|
|
390
|
+
// @ts-expect-error ConsoleProp vs LogSeverity mismatch
|
|
391
|
+
logSubErrors(level, subErrors);
|
|
392
|
+
});
|
|
393
|
+
return [level, freeze(levelMethod)];
|
|
394
|
+
});
|
|
395
|
+
const otherMethodNames = arrayFilter(
|
|
396
|
+
consoleOtherMethods,
|
|
397
|
+
([name, _]) => name in baseConsole,
|
|
398
|
+
);
|
|
399
|
+
const otherMethods = arrayMap(otherMethodNames, ([name, _]) => {
|
|
400
|
+
/**
|
|
401
|
+
* @param {...any} args
|
|
402
|
+
*/
|
|
403
|
+
const otherMethod = defineName(name, (...args) => {
|
|
404
|
+
// @ts-ignore
|
|
405
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
406
|
+
baseConsole[name](...args);
|
|
407
|
+
return undefined;
|
|
408
|
+
});
|
|
409
|
+
return [name, freeze(otherMethod)];
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const causalConsole = fromEntries([...levelMethods, ...otherMethods]);
|
|
413
|
+
return /** @type {VirtualConsole} */ (freeze(causalConsole));
|
|
414
|
+
};
|
|
415
|
+
freeze(makeCausalConsole);
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* @typedef {(...args: unknown[]) => void} Logger
|
|
419
|
+
*/
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* This is a rather horrible kludge to indent the output to a logger in
|
|
423
|
+
* the case where some arguments are strings containing newlines. Part of
|
|
424
|
+
* the problem is that console-like loggers, including the one in ava,
|
|
425
|
+
* join the string arguments of the log message with a space.
|
|
426
|
+
* Because of this, there's an extra space at the beginning of each of
|
|
427
|
+
* the split lines. So this kludge compensated by putting an extra empty
|
|
428
|
+
* string at the beginning, so that the logger will add the same extra
|
|
429
|
+
* joiner.
|
|
430
|
+
* TODO: Fix this horrible kludge, and indent in a sane manner.
|
|
431
|
+
*
|
|
432
|
+
* @param {string} str
|
|
433
|
+
* @param {string} sep
|
|
434
|
+
* @param {string[]} indents
|
|
435
|
+
* @returns {string[]}
|
|
436
|
+
*/
|
|
437
|
+
const indentAfterAllSeps = (str, sep, indents) => {
|
|
438
|
+
const [firstLine, ...restLines] = stringSplit(str, sep);
|
|
439
|
+
const indentedRest = arrayFlatMap(restLines, line => [sep, ...indents, line]);
|
|
440
|
+
return ['', firstLine, ...indentedRest];
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* @param {LoggedErrorHandler} loggedErrorHandler
|
|
445
|
+
*/
|
|
446
|
+
export const defineCausalConsoleFromLogger = loggedErrorHandler => {
|
|
447
|
+
/**
|
|
448
|
+
* Implement the `VirtualConsole` API badly by turning all calls into
|
|
449
|
+
* calls on `tlogger`. We need to do this to have `console` logging
|
|
450
|
+
* turn into calls to Ava's `t.log`, so these console log messages
|
|
451
|
+
* are output in the right place.
|
|
452
|
+
*
|
|
453
|
+
* @param {Logger} tlogger
|
|
454
|
+
* @returns {VirtualConsole}
|
|
455
|
+
*/
|
|
456
|
+
const makeCausalConsoleFromLogger = tlogger => {
|
|
457
|
+
const indents = [];
|
|
458
|
+
const logWithIndent = (...args) => {
|
|
459
|
+
if (indents.length > 0) {
|
|
460
|
+
args = arrayFlatMap(args, arg =>
|
|
461
|
+
typeof arg === 'string' && stringIncludes(arg, '\n')
|
|
462
|
+
? indentAfterAllSeps(arg, '\n', indents)
|
|
463
|
+
: [arg],
|
|
464
|
+
);
|
|
465
|
+
args = [...indents, ...args];
|
|
466
|
+
}
|
|
467
|
+
return tlogger(...args);
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const baseConsole = fromEntries([
|
|
471
|
+
...arrayMap(consoleLevelMethods, ([name]) => [
|
|
472
|
+
name,
|
|
473
|
+
defineName(name, (...args) => logWithIndent(...args)),
|
|
474
|
+
]),
|
|
475
|
+
...arrayMap(consoleOtherMethods, ([name]) => [
|
|
476
|
+
name,
|
|
477
|
+
defineName(name, (...args) => logWithIndent(name, ...args)),
|
|
478
|
+
]),
|
|
479
|
+
]);
|
|
480
|
+
// https://console.spec.whatwg.org/#grouping
|
|
481
|
+
for (const name of ['group', 'groupCollapsed']) {
|
|
482
|
+
if (baseConsole[name]) {
|
|
483
|
+
baseConsole[name] = defineName(name, (...args) => {
|
|
484
|
+
if (args.length >= 1) {
|
|
485
|
+
// Prefix the logged data with "group" or "groupCollapsed".
|
|
486
|
+
logWithIndent(...args);
|
|
487
|
+
}
|
|
488
|
+
// A single space is enough;
|
|
489
|
+
// the host console will separate them with additional spaces.
|
|
490
|
+
arrayPush(indents, ' ');
|
|
491
|
+
});
|
|
492
|
+
} else {
|
|
493
|
+
baseConsole[name] = defineName(name, () => {});
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
baseConsole.groupEnd = defineName(
|
|
497
|
+
'groupEnd',
|
|
498
|
+
baseConsole.groupEnd
|
|
499
|
+
? (...args) => {
|
|
500
|
+
arrayPop(indents);
|
|
501
|
+
}
|
|
502
|
+
: () => {},
|
|
503
|
+
);
|
|
504
|
+
harden(baseConsole);
|
|
505
|
+
const causalConsole = makeCausalConsole(
|
|
506
|
+
/** @type {VirtualConsole} */ (baseConsole),
|
|
507
|
+
loggedErrorHandler,
|
|
508
|
+
);
|
|
509
|
+
return /** @type {VirtualConsole} */ (causalConsole);
|
|
510
|
+
};
|
|
511
|
+
return freeze(makeCausalConsoleFromLogger);
|
|
512
|
+
};
|
|
513
|
+
freeze(defineCausalConsoleFromLogger);
|
|
514
|
+
|
|
515
|
+
// ///////////////////////// Filter Console ////////////////////////////////////
|
|
516
|
+
|
|
517
|
+
/** @type {FilterConsole} */
|
|
518
|
+
export const filterConsole = (baseConsole, filter, _topic = undefined) => {
|
|
519
|
+
// TODO do something with optional topic string
|
|
520
|
+
const methodPermits = arrayFilter(
|
|
521
|
+
consoleMethodPermits,
|
|
522
|
+
([name, _]) => name in baseConsole,
|
|
523
|
+
);
|
|
524
|
+
const methods = arrayMap(methodPermits, ([name, severity]) => {
|
|
525
|
+
/**
|
|
526
|
+
* @param {...any} args
|
|
527
|
+
*/
|
|
528
|
+
const method = defineName(name, (...args) => {
|
|
529
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
530
|
+
if (severity === undefined || filter.canLog(severity)) {
|
|
531
|
+
// @ts-ignore
|
|
532
|
+
// eslint-disable-next-line @endo/no-polymorphic-call
|
|
533
|
+
baseConsole[name](...args);
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
return [name, freeze(method)];
|
|
537
|
+
});
|
|
538
|
+
const filteringConsole = fromEntries(methods);
|
|
539
|
+
return /** @type {VirtualConsole} */ (freeze(filteringConsole));
|
|
540
|
+
};
|
|
541
|
+
freeze(filterConsole);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/* global process */
|
|
3
|
+
|
|
4
|
+
import { freeze } from '../commons.js';
|
|
5
|
+
import { makeAssert } from './assert.js';
|
|
6
|
+
import './types.js';
|
|
7
|
+
|
|
8
|
+
/** @import {Assert} from '../../types.js' */
|
|
9
|
+
|
|
10
|
+
let abandon;
|
|
11
|
+
// Sniff for host-provided functions for terminating the enclosing UOPT (see
|
|
12
|
+
// below). Currently it only checks for the `process.abort` or `process.exit`
|
|
13
|
+
// found on Node. It should also sniff for a vat terminating function expected
|
|
14
|
+
// to be found within the start compartment of SwingSet vats. What else?
|
|
15
|
+
if (typeof process === 'object' && process) {
|
|
16
|
+
abandon = process.abort || process.exit;
|
|
17
|
+
}
|
|
18
|
+
let raise;
|
|
19
|
+
if (typeof abandon === 'function') {
|
|
20
|
+
/** @param {Error} reason */
|
|
21
|
+
raise = reason => {
|
|
22
|
+
// Check `console` each time `raise` is called.
|
|
23
|
+
// eslint-disable-next-line no-restricted-globals
|
|
24
|
+
if (typeof console === 'object' && typeof console.error === 'function') {
|
|
25
|
+
// eslint-disable-next-line @endo/no-polymorphic-call, no-restricted-globals
|
|
26
|
+
console.error('Failed because:', reason);
|
|
27
|
+
}
|
|
28
|
+
abandon(1);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @type {Partial<{assert: Assert}>}
|
|
34
|
+
*
|
|
35
|
+
* When run in the start compartment, this sniffs to see if there are known
|
|
36
|
+
* forms of host-provided functions for immediately terminating the enclosing
|
|
37
|
+
* Unit of Preemptive Termination. If so, we initialize the exported
|
|
38
|
+
* `fatal` object with its own `assert`, which is like the global `assert`.
|
|
39
|
+
* But rather than throwing the error as global `assert` does,
|
|
40
|
+
* `fatal.assert` logs the error to the current `console`, if any, and terminates
|
|
41
|
+
* this unit of computation.
|
|
42
|
+
*
|
|
43
|
+
* See https://github.com/tc39/proposal-oom-fails-fast for the meaning of a
|
|
44
|
+
* "Unit of Preemptive Termination" (UOPT). This is a unit of
|
|
45
|
+
* computation---like the vat, worker, or process---containing the potentially
|
|
46
|
+
* corrupted state. We preemptively terminate it in order to abandon that
|
|
47
|
+
* corrupted state.
|
|
48
|
+
*/
|
|
49
|
+
const fatal = {};
|
|
50
|
+
if (raise) {
|
|
51
|
+
fatal.assert = makeAssert(raise);
|
|
52
|
+
}
|
|
53
|
+
freeze(fatal);
|
|
54
|
+
export { fatal };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @import {VirtualConsole} from './types.js'
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {readonly any[]} LogArgs
|
|
9
|
+
*
|
|
10
|
+
* This is an array suitable to be used as arguments of a console
|
|
11
|
+
* level message *after* the format string argument. It is the result of
|
|
12
|
+
* a `details` template string and consists of alternating literal strings
|
|
13
|
+
* and substitution values, starting with a literal string. At least that
|
|
14
|
+
* first literal string is always present.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @callback NoteCallback
|
|
19
|
+
*
|
|
20
|
+
* @param {Error} error
|
|
21
|
+
* @param {LogArgs} noteLogArgs
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @callback GetStackString
|
|
27
|
+
* @param {Error} error
|
|
28
|
+
* @returns {string=}
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {object} LoggedErrorHandler
|
|
33
|
+
*
|
|
34
|
+
* Used to parameterize `makeCausalConsole` to give it access to potentially
|
|
35
|
+
* hidden information to augment the logging of errors.
|
|
36
|
+
*
|
|
37
|
+
* @property {GetStackString} getStackString
|
|
38
|
+
* @property {(error: Error) => string} tagError
|
|
39
|
+
* @property {() => void} resetErrorTagNum for debugging purposes only
|
|
40
|
+
* @property {(error: Error) => (LogArgs | undefined)} getMessageLogArgs
|
|
41
|
+
* @property {(error: Error) => (LogArgs | undefined)} takeMessageLogArgs
|
|
42
|
+
* @property {(error: Error, callback?: NoteCallback) => LogArgs[] } takeNoteLogArgsArray
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
// /////////////////////////////////////////////////////////////////////////////
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {readonly [string, ...any[]]} LogRecord
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {object} LoggingConsoleKit
|
|
53
|
+
* @property {VirtualConsole} loggingConsole
|
|
54
|
+
* @property {() => readonly LogRecord[]} takeLog
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @typedef {object} MakeLoggingConsoleKitOptions
|
|
59
|
+
* @property {boolean=} shouldResetForDebugging
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @callback MakeLoggingConsoleKit
|
|
64
|
+
*
|
|
65
|
+
* A logging console just accumulates the contents of all permitted calls,
|
|
66
|
+
* making them available to callers of `takeLog()`. Calling `takeLog()`
|
|
67
|
+
* consumes these, so later calls to `takeLog()` will only provide a log of
|
|
68
|
+
* calls that have happened since then.
|
|
69
|
+
*
|
|
70
|
+
* @param {LoggedErrorHandler} loggedErrorHandler
|
|
71
|
+
* @param {MakeLoggingConsoleKitOptions=} options
|
|
72
|
+
* @returns {LoggingConsoleKit}
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @typedef {{
|
|
77
|
+
* NOTE: 'ERROR_NOTE:',
|
|
78
|
+
* MESSAGE: 'ERROR_MESSAGE:',
|
|
79
|
+
* CAUSE: 'cause:',
|
|
80
|
+
* ERRORS: 'errors:',
|
|
81
|
+
* }} ErrorInfo
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @typedef {ErrorInfo[keyof ErrorInfo]} ErrorInfoKind
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @callback MakeCausalConsole
|
|
90
|
+
*
|
|
91
|
+
* Makes a causal console wrapper of a `baseConsole`, where the causal console
|
|
92
|
+
* calls methods of the `loggedErrorHandler` to customize how it handles logged
|
|
93
|
+
* errors.
|
|
94
|
+
*
|
|
95
|
+
* @param {VirtualConsole | undefined} baseConsole
|
|
96
|
+
* @param {LoggedErrorHandler} loggedErrorHandler
|
|
97
|
+
* @returns {VirtualConsole | undefined}
|
|
98
|
+
*/
|