@pokujs/dom 0.0.1 → 1.1.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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/dom-env.d.ts +9 -0
- package/dist/dom-env.js +59 -0
- package/dist/dom-env.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-command.d.ts +22 -0
- package/dist/plugin-command.js +94 -0
- package/dist/plugin-command.js.map +1 -0
- package/dist/plugin-factory.d.ts +21 -0
- package/dist/plugin-factory.js +117 -0
- package/dist/plugin-factory.js.map +1 -0
- package/dist/plugin-metrics.d.ts +19 -0
- package/dist/plugin-metrics.js +93 -0
- package/dist/plugin-metrics.js.map +1 -0
- package/dist/plugin-setup.d.ts +8 -0
- package/dist/plugin-setup.js +50 -0
- package/dist/plugin-setup.js.map +1 -0
- package/dist/runtime-options.d.ts +3 -0
- package/dist/runtime-options.js +48 -0
- package/dist/runtime-options.js.map +1 -0
- package/dist/testing-core.d.ts +14 -0
- package/dist/testing-core.js +114 -0
- package/dist/testing-core.js.map +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +82 -3
- package/index.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lojhan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img height="180" alt="Poku Logo" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/poku.svg">
|
|
3
|
+
|
|
4
|
+
# @pokujs/dom
|
|
5
|
+
|
|
6
|
+
Shared DOM testing core for Poku framework adapters.
|
|
7
|
+
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
@pokujs/dom centralizes cross-framework testing infrastructure used by adapter libraries such as @pokujs/react and @pokujs/vue.
|
|
13
|
+
|
|
14
|
+
Use this package when building or maintaining framework adapters that need:
|
|
15
|
+
|
|
16
|
+
- Runtime command injection for Node, Bun, and Deno.
|
|
17
|
+
- In-process test environment setup.
|
|
18
|
+
- Metrics normalization and reporting.
|
|
19
|
+
- happy-dom/jsdom environment bootstrap.
|
|
20
|
+
- Shared testing runtime primitives.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i @pokujs/dom
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### 1) Build runtime option prefixes and parse flags
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import {
|
|
34
|
+
createRuntimeOptionArgPrefixes,
|
|
35
|
+
parseRuntimeOptions,
|
|
36
|
+
} from '@pokujs/dom';
|
|
37
|
+
|
|
38
|
+
const prefixes = createRuntimeOptionArgPrefixes('poku-react');
|
|
39
|
+
const runtimeOptions = parseRuntimeOptions(prefixes);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2) Create a framework plugin factory
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import {
|
|
46
|
+
createFrameworkTestingPluginFactory,
|
|
47
|
+
type FrameworkDescriptor,
|
|
48
|
+
} from '@pokujs/dom';
|
|
49
|
+
|
|
50
|
+
const descriptor: FrameworkDescriptor = {
|
|
51
|
+
pluginName: 'react-testing',
|
|
52
|
+
packageTag: '@pokujs/react',
|
|
53
|
+
runtimeArgBase: 'poku-react',
|
|
54
|
+
metricMessageType: 'POKU_REACT_RENDER_METRIC',
|
|
55
|
+
metricBatchMessageType: 'POKU_REACT_RENDER_METRIC_BATCH',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const { createTestingPlugin } = createFrameworkTestingPluginFactory(
|
|
59
|
+
descriptor,
|
|
60
|
+
import.meta.url
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export const createReactTestingPlugin = createTestingPlugin;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3) Reuse DOM setup helpers
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { setupHappyDomEnvironment, setupJsdomEnvironment } from '@pokujs/dom';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 4) Reuse shared testing runtime helpers
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import {
|
|
76
|
+
createRenderMetricsEmitter,
|
|
77
|
+
createScreen,
|
|
78
|
+
getNow,
|
|
79
|
+
} from '@pokujs/dom';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Contracts
|
|
83
|
+
|
|
84
|
+
Adapter packages should follow these contracts.
|
|
85
|
+
|
|
86
|
+
### FrameworkDescriptor contract
|
|
87
|
+
|
|
88
|
+
- pluginName: Plugin registration name.
|
|
89
|
+
- packageTag: Human-readable package tag for messages.
|
|
90
|
+
- runtimeArgBase: Prefix base used to generate runtime CLI flags.
|
|
91
|
+
- metricMessageType: IPC type for single render metrics.
|
|
92
|
+
- metricBatchMessageType: IPC type for batch render metrics.
|
|
93
|
+
- testFileExtensions (optional): Test file extensions the runner should intercept.
|
|
94
|
+
|
|
95
|
+
### Runtime options contract
|
|
96
|
+
|
|
97
|
+
parseRuntimeOptions returns:
|
|
98
|
+
|
|
99
|
+
- domUrl: DOM URL used by happy-dom/jsdom setup.
|
|
100
|
+
- metricsEnabled: Whether metrics collection is active.
|
|
101
|
+
- minMetricMs: Drop metrics below this threshold.
|
|
102
|
+
- metricBatchSize: Batch size before immediate flush.
|
|
103
|
+
- metricFlushMs: Flush interval while buffering.
|
|
104
|
+
|
|
105
|
+
### Metrics contract
|
|
106
|
+
|
|
107
|
+
createMetricsSummary returns either null or:
|
|
108
|
+
|
|
109
|
+
- totalCaptured: Number of collected metrics.
|
|
110
|
+
- totalReported: Number of top metrics reported.
|
|
111
|
+
- topSlowest: Sorted metrics by duration descending.
|
|
112
|
+
|
|
113
|
+
### Testing runtime contract
|
|
114
|
+
|
|
115
|
+
createRenderMetricsEmitter provides:
|
|
116
|
+
|
|
117
|
+
- emitRenderMetric(componentName, durationMs)
|
|
118
|
+
- flushMetricBuffer()
|
|
119
|
+
- clearMetricFlushTimer()
|
|
120
|
+
|
|
121
|
+
These APIs are framework-agnostic. Adapter packages remain responsible for framework-specific semantics such as act, nextTick, render lifecycle, and hook/composable harness behavior.
|
|
122
|
+
|
|
123
|
+
## Release and CI/CD
|
|
124
|
+
|
|
125
|
+
This package includes:
|
|
126
|
+
|
|
127
|
+
- CI build and lint workflows.
|
|
128
|
+
- Node, Bun, and Deno compatibility workflows.
|
|
129
|
+
- CodeQL workflow and config.
|
|
130
|
+
- Release Please + npm publish workflow.
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm ci
|
|
136
|
+
npm run check
|
|
137
|
+
npm run build
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Testing
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm test
|
|
144
|
+
npm run test:bun
|
|
145
|
+
npm run test:deno
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RuntimeOptions } from './types.ts';
|
|
2
|
+
type SetupDomEnvironmentOptions = {
|
|
3
|
+
runtimeOptions: RuntimeOptions;
|
|
4
|
+
packageTag: string;
|
|
5
|
+
enableReactActEnvironment?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare const setupHappyDomEnvironment: (options: SetupDomEnvironmentOptions) => Promise<void>;
|
|
8
|
+
export declare const setupJsdomEnvironment: (options: SetupDomEnvironmentOptions) => Promise<void>;
|
|
9
|
+
export {};
|
package/dist/dom-env.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { GlobalRegistrator } from '@happy-dom/global-registrator';
|
|
2
|
+
const applyReactActEnvironment = (enabled) => {
|
|
3
|
+
if (!enabled)
|
|
4
|
+
return;
|
|
5
|
+
const reactGlobal = globalThis;
|
|
6
|
+
if (typeof reactGlobal.IS_REACT_ACT_ENVIRONMENT === 'undefined') {
|
|
7
|
+
reactGlobal.IS_REACT_ACT_ENVIRONMENT = true;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const setupHappyDomEnvironment = async (options) => {
|
|
11
|
+
if (!globalThis.window || !globalThis.document) {
|
|
12
|
+
GlobalRegistrator.register({
|
|
13
|
+
url: options.runtimeOptions.domUrl,
|
|
14
|
+
});
|
|
15
|
+
const nativeDispatchEvent = globalThis.window.dispatchEvent;
|
|
16
|
+
if (typeof nativeDispatchEvent === 'function') {
|
|
17
|
+
globalThis.dispatchEvent = nativeDispatchEvent.bind(globalThis.window);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
applyReactActEnvironment(Boolean(options.enableReactActEnvironment));
|
|
21
|
+
};
|
|
22
|
+
const defineGlobal = (key, value) => {
|
|
23
|
+
Object.defineProperty(globalThis, key, {
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value,
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
export const setupJsdomEnvironment = async (options) => {
|
|
30
|
+
if (!globalThis.window || !globalThis.document) {
|
|
31
|
+
let mod;
|
|
32
|
+
try {
|
|
33
|
+
mod = await import('jsdom');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error(`[${options.packageTag}] DOM adapter "jsdom" requires the "jsdom" package. Install it with "npm install --save-dev jsdom".`);
|
|
37
|
+
}
|
|
38
|
+
const { JSDOM } = mod;
|
|
39
|
+
const dom = new JSDOM('', {
|
|
40
|
+
url: options.runtimeOptions.domUrl,
|
|
41
|
+
pretendToBeVisual: true,
|
|
42
|
+
});
|
|
43
|
+
defineGlobal('window', dom.window);
|
|
44
|
+
defineGlobal('document', dom.window.document);
|
|
45
|
+
defineGlobal('navigator', dom.window.navigator);
|
|
46
|
+
defineGlobal('HTMLElement', dom.window.HTMLElement);
|
|
47
|
+
defineGlobal('Element', dom.window.Element);
|
|
48
|
+
defineGlobal('Node', dom.window.Node);
|
|
49
|
+
defineGlobal('Text', dom.window.Text);
|
|
50
|
+
defineGlobal('SVGElement', dom.window.SVGElement);
|
|
51
|
+
defineGlobal('Event', dom.window.Event);
|
|
52
|
+
defineGlobal('CustomEvent', dom.window.CustomEvent);
|
|
53
|
+
defineGlobal('MutationObserver', dom.window.MutationObserver);
|
|
54
|
+
defineGlobal('requestAnimationFrame', dom.window.requestAnimationFrame);
|
|
55
|
+
defineGlobal('cancelAnimationFrame', dom.window.cancelAnimationFrame);
|
|
56
|
+
}
|
|
57
|
+
applyReactActEnvironment(Boolean(options.enableReactActEnvironment));
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=dom-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-env.js","sourceRoot":"","sources":["../src/dom-env.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './types.ts';
|
|
2
|
+
export * from './runtime-options.ts';
|
|
3
|
+
export * from './plugin-command.ts';
|
|
4
|
+
export * from './plugin-setup.ts';
|
|
5
|
+
export * from './plugin-metrics.ts';
|
|
6
|
+
export * from './plugin-factory.ts';
|
|
7
|
+
export * from './dom-env.ts';
|
|
8
|
+
export * from './testing-core.ts';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./runtime-options.js";
|
|
3
|
+
export * from "./plugin-command.js";
|
|
4
|
+
export * from "./plugin-setup.js";
|
|
5
|
+
export * from "./plugin-metrics.js";
|
|
6
|
+
export * from "./plugin-factory.js";
|
|
7
|
+
export * from "./dom-env.js";
|
|
8
|
+
export * from "./testing-core.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomAdapter } from './types.ts';
|
|
2
|
+
export type RuntimeSupport = {
|
|
3
|
+
supportsNodeLikeImport: boolean;
|
|
4
|
+
supportsDenoPreload: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type BuildRunnerCommandInput = {
|
|
7
|
+
runtime: string;
|
|
8
|
+
command: string[];
|
|
9
|
+
file: string;
|
|
10
|
+
domSetupPath: string;
|
|
11
|
+
runtimeOptionArgs: string[];
|
|
12
|
+
extensions: Set<string>;
|
|
13
|
+
};
|
|
14
|
+
export type BuildRunnerCommandOutput = {
|
|
15
|
+
shouldHandle: boolean;
|
|
16
|
+
command: string[];
|
|
17
|
+
};
|
|
18
|
+
export declare const isNodeRuntime: (runtime: string) => runtime is "node";
|
|
19
|
+
export declare const getRuntimeSupport: (runtime: string) => RuntimeSupport;
|
|
20
|
+
export declare const canHandleRuntime: (runtime: string) => boolean;
|
|
21
|
+
export declare const createDomSetupPathResolver: (packageTag: string, happyDomSetupPath: string, jsdomSetupPath: string) => (adapter: DomAdapter | undefined) => string;
|
|
22
|
+
export declare const buildRunnerCommand: ({ runtime, command, file, domSetupPath, runtimeOptionArgs, extensions, }: BuildRunnerCommandInput) => BuildRunnerCommandOutput;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { extname, resolve } from 'node:path';
|
|
3
|
+
const isTsxImport = (arg) => arg === '--import=tsx' || arg === '--loader=tsx';
|
|
4
|
+
export const isNodeRuntime = (runtime) => runtime === 'node';
|
|
5
|
+
const isBunRuntime = (runtime) => runtime === 'bun';
|
|
6
|
+
const isDenoRuntime = (runtime) => runtime === 'deno';
|
|
7
|
+
export const getRuntimeSupport = (runtime) => ({
|
|
8
|
+
supportsNodeLikeImport: isNodeRuntime(runtime) || isBunRuntime(runtime),
|
|
9
|
+
supportsDenoPreload: isDenoRuntime(runtime),
|
|
10
|
+
});
|
|
11
|
+
export const canHandleRuntime = (runtime) => {
|
|
12
|
+
const support = getRuntimeSupport(runtime);
|
|
13
|
+
return support.supportsNodeLikeImport || support.supportsDenoPreload;
|
|
14
|
+
};
|
|
15
|
+
export const createDomSetupPathResolver = (packageTag, happyDomSetupPath, jsdomSetupPath) => {
|
|
16
|
+
return (adapter) => {
|
|
17
|
+
if (!adapter || adapter === 'happy-dom')
|
|
18
|
+
return happyDomSetupPath;
|
|
19
|
+
if (adapter === 'jsdom')
|
|
20
|
+
return jsdomSetupPath;
|
|
21
|
+
const customPath = resolve(process.cwd(), adapter.setupModule);
|
|
22
|
+
if (!existsSync(customPath)) {
|
|
23
|
+
throw new Error(`[${packageTag}] Custom DOM setup module not found: "${customPath}"\n` +
|
|
24
|
+
'Check the "dom.setupModule" option in your poku.config.js.');
|
|
25
|
+
}
|
|
26
|
+
return customPath;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export const buildRunnerCommand = ({ runtime, command, file, domSetupPath, runtimeOptionArgs, extensions, }) => {
|
|
30
|
+
const support = getRuntimeSupport(runtime);
|
|
31
|
+
if (!support.supportsNodeLikeImport && !support.supportsDenoPreload) {
|
|
32
|
+
return { shouldHandle: false, command };
|
|
33
|
+
}
|
|
34
|
+
if (!extensions.has(extname(file))) {
|
|
35
|
+
return { shouldHandle: false, command };
|
|
36
|
+
}
|
|
37
|
+
const fileIndex = command.lastIndexOf(file);
|
|
38
|
+
if (fileIndex === -1)
|
|
39
|
+
return { shouldHandle: false, command };
|
|
40
|
+
const nodeImportFlag = `--import=${domSetupPath}`;
|
|
41
|
+
const denoPreloadFlag = `--preload=${domSetupPath}`;
|
|
42
|
+
const beforeFile = [];
|
|
43
|
+
const afterFile = [];
|
|
44
|
+
let hasTsx = false;
|
|
45
|
+
let hasNodeLikeDomSetup = false;
|
|
46
|
+
let hasDenoDomSetup = false;
|
|
47
|
+
const existingArgs = new Set();
|
|
48
|
+
for (let index = 1; index < command.length; index += 1) {
|
|
49
|
+
const arg = command[index];
|
|
50
|
+
if (typeof arg !== 'string')
|
|
51
|
+
continue;
|
|
52
|
+
existingArgs.add(arg);
|
|
53
|
+
if (index < fileIndex) {
|
|
54
|
+
beforeFile.push(arg);
|
|
55
|
+
if (isTsxImport(arg))
|
|
56
|
+
hasTsx = true;
|
|
57
|
+
else if (arg === nodeImportFlag)
|
|
58
|
+
hasNodeLikeDomSetup = true;
|
|
59
|
+
else if (arg === denoPreloadFlag)
|
|
60
|
+
hasDenoDomSetup = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (index > fileIndex) {
|
|
64
|
+
afterFile.push(arg);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const extraImports = [];
|
|
68
|
+
if (isNodeRuntime(runtime) && !hasTsx)
|
|
69
|
+
extraImports.push('--import=tsx');
|
|
70
|
+
if (support.supportsNodeLikeImport && !hasNodeLikeDomSetup) {
|
|
71
|
+
extraImports.push(nodeImportFlag);
|
|
72
|
+
}
|
|
73
|
+
if (support.supportsDenoPreload && !hasDenoDomSetup) {
|
|
74
|
+
extraImports.push(denoPreloadFlag);
|
|
75
|
+
}
|
|
76
|
+
const runtimeArgsToInject = [];
|
|
77
|
+
for (const runtimeOptionArg of runtimeOptionArgs) {
|
|
78
|
+
if (existingArgs.has(runtimeOptionArg))
|
|
79
|
+
continue;
|
|
80
|
+
runtimeArgsToInject.push(runtimeOptionArg);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
shouldHandle: true,
|
|
84
|
+
command: [
|
|
85
|
+
runtime,
|
|
86
|
+
...beforeFile,
|
|
87
|
+
...extraImports,
|
|
88
|
+
file,
|
|
89
|
+
...runtimeArgsToInject,
|
|
90
|
+
...afterFile,
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=plugin-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-command.js","sourceRoot":"","sources":["../src/plugin-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DomAdapter, FrameworkDescriptor, TestingPluginOptions } from './types.ts';
|
|
2
|
+
import { buildRunnerCommand, canHandleRuntime } from './plugin-command.ts';
|
|
3
|
+
import { buildRuntimeOptionArgs, createMetricsSummary, getComponentName, isRenderMetricBatchMessage, isRenderMetricMessage, normalizeMetricsOptions, selectTopSlowestMetrics } from './plugin-metrics.ts';
|
|
4
|
+
export type FrameworkPluginInternals = {
|
|
5
|
+
buildRunnerCommand: typeof buildRunnerCommand;
|
|
6
|
+
canHandleRuntime: typeof canHandleRuntime;
|
|
7
|
+
buildRuntimeOptionArgs: typeof buildRuntimeOptionArgs;
|
|
8
|
+
normalizeMetricsOptions: typeof normalizeMetricsOptions;
|
|
9
|
+
selectTopSlowestMetrics: typeof selectTopSlowestMetrics;
|
|
10
|
+
createMetricsSummary: typeof createMetricsSummary;
|
|
11
|
+
getComponentName: typeof getComponentName;
|
|
12
|
+
isRenderMetricMessage: typeof isRenderMetricMessage;
|
|
13
|
+
isRenderMetricBatchMessage: typeof isRenderMetricBatchMessage;
|
|
14
|
+
resolveDomSetupPath: (adapter: DomAdapter | undefined) => string;
|
|
15
|
+
};
|
|
16
|
+
export declare const createFrameworkTestingPluginFactory: (descriptor: FrameworkDescriptor, moduleUrl: string) => {
|
|
17
|
+
createTestingPlugin: (options?: TestingPluginOptions) => any;
|
|
18
|
+
resolveDomSetupPath: (adapter: DomAdapter | undefined) => string;
|
|
19
|
+
runtimeOptionArgPrefixes: import("./types.ts").RuntimeOptionArgPrefixes;
|
|
20
|
+
internals: FrameworkPluginInternals;
|
|
21
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { definePlugin } from 'poku/plugins';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { buildRunnerCommand, canHandleRuntime, createDomSetupPathResolver, } from "./plugin-command.js";
|
|
6
|
+
import { buildRuntimeOptionArgs, createMetricsSummary, getComponentName, isRenderMetricBatchMessage, isRenderMetricMessage, normalizeMetricsOptions, printMetricsSummary, selectTopSlowestMetrics, } from "./plugin-metrics.js";
|
|
7
|
+
import { setupInProcessEnvironment } from "./plugin-setup.js";
|
|
8
|
+
import { createRuntimeOptionArgPrefixes } from "./runtime-options.js";
|
|
9
|
+
export const createFrameworkTestingPluginFactory = (descriptor, moduleUrl) => {
|
|
10
|
+
const currentDir = dirname(fileURLToPath(moduleUrl));
|
|
11
|
+
const resolveSetupModulePath = (baseName) => {
|
|
12
|
+
const jsPath = resolve(currentDir, `${baseName}.js`);
|
|
13
|
+
if (existsSync(jsPath))
|
|
14
|
+
return jsPath;
|
|
15
|
+
return resolve(currentDir, `${baseName}.ts`);
|
|
16
|
+
};
|
|
17
|
+
const happyDomSetupPath = resolveSetupModulePath('dom-setup-happy');
|
|
18
|
+
const jsdomSetupPath = resolveSetupModulePath('dom-setup-jsdom');
|
|
19
|
+
const resolveDomSetupPath = createDomSetupPathResolver(descriptor.packageTag, happyDomSetupPath, jsdomSetupPath);
|
|
20
|
+
const prefixes = createRuntimeOptionArgPrefixes(descriptor.runtimeArgBase);
|
|
21
|
+
const extensions = new Set(descriptor.testFileExtensions ?? ['.tsx', '.jsx']);
|
|
22
|
+
const createTestingPlugin = (options = {}) => {
|
|
23
|
+
let metrics = [];
|
|
24
|
+
let cleanupNodeTsxLoader;
|
|
25
|
+
const domSetupPath = resolveDomSetupPath(options.dom);
|
|
26
|
+
const metricsOptions = normalizeMetricsOptions(options.metrics);
|
|
27
|
+
const runtimeOptionArgs = buildRuntimeOptionArgs(options, metricsOptions, prefixes);
|
|
28
|
+
return definePlugin({
|
|
29
|
+
name: descriptor.pluginName,
|
|
30
|
+
ipc: metricsOptions.enabled,
|
|
31
|
+
async setup(context) {
|
|
32
|
+
cleanupNodeTsxLoader = await setupInProcessEnvironment({
|
|
33
|
+
isolation: context.configs.isolation,
|
|
34
|
+
runtime: context.runtime,
|
|
35
|
+
runtimeOptionArgs,
|
|
36
|
+
domSetupPath,
|
|
37
|
+
packageTag: descriptor.packageTag,
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
runner(command, file) {
|
|
41
|
+
const runtime = command[0];
|
|
42
|
+
if (!runtime)
|
|
43
|
+
return command;
|
|
44
|
+
const result = descriptor.commandBuilder
|
|
45
|
+
? descriptor.commandBuilder({ runtime, command, file, domSetupPath, runtimeOptionArgs })
|
|
46
|
+
: buildRunnerCommand({ runtime, command, file, domSetupPath, runtimeOptionArgs, extensions });
|
|
47
|
+
if (!result.shouldHandle)
|
|
48
|
+
return command;
|
|
49
|
+
return result.command;
|
|
50
|
+
},
|
|
51
|
+
onTestProcess(child, file) {
|
|
52
|
+
if (!metricsOptions.enabled)
|
|
53
|
+
return;
|
|
54
|
+
const maybePruneMetrics = () => {
|
|
55
|
+
if (metrics.length > metricsOptions.topN * 10) {
|
|
56
|
+
metrics = selectTopSlowestMetrics(metrics, metricsOptions);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
child.on('message', (message) => {
|
|
60
|
+
if (isRenderMetricBatchMessage(message, descriptor.metricBatchMessageType)) {
|
|
61
|
+
for (const metric of message.metrics) {
|
|
62
|
+
const durationMs = Number(metric.durationMs) || 0;
|
|
63
|
+
metrics.push({
|
|
64
|
+
file,
|
|
65
|
+
componentName: getComponentName(metric.componentName),
|
|
66
|
+
durationMs,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
maybePruneMetrics();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (!isRenderMetricMessage(message, descriptor.metricMessageType)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const durationMs = Number(message.durationMs) || 0;
|
|
76
|
+
metrics.push({
|
|
77
|
+
file,
|
|
78
|
+
componentName: getComponentName(message.componentName),
|
|
79
|
+
durationMs,
|
|
80
|
+
});
|
|
81
|
+
maybePruneMetrics();
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
teardown() {
|
|
85
|
+
cleanupNodeTsxLoader?.();
|
|
86
|
+
cleanupNodeTsxLoader = undefined;
|
|
87
|
+
const summary = createMetricsSummary(metrics, metricsOptions);
|
|
88
|
+
if (!summary)
|
|
89
|
+
return;
|
|
90
|
+
if (metricsOptions.reporter) {
|
|
91
|
+
metricsOptions.reporter(summary);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
printMetricsSummary(summary, descriptor.packageTag);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const internals = {
|
|
99
|
+
buildRunnerCommand,
|
|
100
|
+
canHandleRuntime,
|
|
101
|
+
buildRuntimeOptionArgs,
|
|
102
|
+
normalizeMetricsOptions,
|
|
103
|
+
selectTopSlowestMetrics,
|
|
104
|
+
createMetricsSummary,
|
|
105
|
+
getComponentName,
|
|
106
|
+
isRenderMetricMessage,
|
|
107
|
+
isRenderMetricBatchMessage,
|
|
108
|
+
resolveDomSetupPath,
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
createTestingPlugin,
|
|
112
|
+
resolveDomSetupPath,
|
|
113
|
+
runtimeOptionArgPrefixes: prefixes,
|
|
114
|
+
internals,
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=plugin-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-factory.js","sourceRoot":"","sources":["../src/plugin-factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MetricsOptions, MetricsSummary, NormalizedMetricsOptions, RenderMetric, RuntimeOptionArgPrefixes, TestingPluginOptions } from './types.ts';
|
|
2
|
+
export declare const isRenderMetricMessage: (message: unknown, metricMessageType: string) => message is {
|
|
3
|
+
type: string;
|
|
4
|
+
componentName?: string;
|
|
5
|
+
durationMs?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const isRenderMetricBatchMessage: (message: unknown, metricBatchMessageType: string) => message is {
|
|
8
|
+
type: string;
|
|
9
|
+
metrics: Array<{
|
|
10
|
+
componentName?: string;
|
|
11
|
+
durationMs?: number;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
export declare const getComponentName: (componentName: unknown) => string;
|
|
15
|
+
export declare const buildRuntimeOptionArgs: (options: TestingPluginOptions, metricsOptions: NormalizedMetricsOptions, prefixes: RuntimeOptionArgPrefixes) => string[];
|
|
16
|
+
export declare const normalizeMetricsOptions: (metrics: boolean | MetricsOptions | undefined) => NormalizedMetricsOptions;
|
|
17
|
+
export declare const selectTopSlowestMetrics: (metrics: RenderMetric[], options: NormalizedMetricsOptions) => RenderMetric[];
|
|
18
|
+
export declare const createMetricsSummary: (metrics: RenderMetric[], options: NormalizedMetricsOptions) => MetricsSummary | null;
|
|
19
|
+
export declare const printMetricsSummary: (summary: MetricsSummary, packageTag: string) => void;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const DEFAULT_TOP_N = 5;
|
|
2
|
+
const DEFAULT_MIN_DURATION_MS = 0;
|
|
3
|
+
export const isRenderMetricMessage = (message, metricMessageType) => {
|
|
4
|
+
if (!message || typeof message !== 'object')
|
|
5
|
+
return false;
|
|
6
|
+
return message.type === metricMessageType;
|
|
7
|
+
};
|
|
8
|
+
export const isRenderMetricBatchMessage = (message, metricBatchMessageType) => {
|
|
9
|
+
if (!message || typeof message !== 'object')
|
|
10
|
+
return false;
|
|
11
|
+
const record = message;
|
|
12
|
+
return (record.type === metricBatchMessageType && Array.isArray(record.metrics));
|
|
13
|
+
};
|
|
14
|
+
export const getComponentName = (componentName) => typeof componentName === 'string' && componentName.length > 0
|
|
15
|
+
? componentName
|
|
16
|
+
: 'AnonymousComponent';
|
|
17
|
+
const getPositiveIntegerOrDefault = (value, fallback) => {
|
|
18
|
+
const numeric = typeof value === 'number'
|
|
19
|
+
? value
|
|
20
|
+
: typeof value === 'string' && value.trim().length > 0
|
|
21
|
+
? Number(value.trim())
|
|
22
|
+
: NaN;
|
|
23
|
+
if (!Number.isFinite(numeric) || numeric <= 0)
|
|
24
|
+
return fallback;
|
|
25
|
+
return Math.floor(numeric);
|
|
26
|
+
};
|
|
27
|
+
const getNonNegativeNumberOrDefault = (value, fallback) => {
|
|
28
|
+
const numeric = typeof value === 'number'
|
|
29
|
+
? value
|
|
30
|
+
: typeof value === 'string' && value.trim().length > 0
|
|
31
|
+
? Number(value.trim())
|
|
32
|
+
: NaN;
|
|
33
|
+
if (!Number.isFinite(numeric) || numeric < 0)
|
|
34
|
+
return fallback;
|
|
35
|
+
return numeric;
|
|
36
|
+
};
|
|
37
|
+
export const buildRuntimeOptionArgs = (options, metricsOptions, prefixes) => {
|
|
38
|
+
const args = [];
|
|
39
|
+
if (options.domUrl) {
|
|
40
|
+
args.push(`${prefixes.domUrl}${options.domUrl}`);
|
|
41
|
+
}
|
|
42
|
+
if (metricsOptions.enabled) {
|
|
43
|
+
args.push(`${prefixes.metrics}1`);
|
|
44
|
+
args.push(`${prefixes.minMetricMs}${metricsOptions.minDurationMs}`);
|
|
45
|
+
}
|
|
46
|
+
return args;
|
|
47
|
+
};
|
|
48
|
+
export const normalizeMetricsOptions = (metrics) => {
|
|
49
|
+
if (metrics === true) {
|
|
50
|
+
return {
|
|
51
|
+
enabled: true,
|
|
52
|
+
topN: DEFAULT_TOP_N,
|
|
53
|
+
minDurationMs: DEFAULT_MIN_DURATION_MS,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (!metrics) {
|
|
57
|
+
return {
|
|
58
|
+
enabled: false,
|
|
59
|
+
topN: DEFAULT_TOP_N,
|
|
60
|
+
minDurationMs: DEFAULT_MIN_DURATION_MS,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const normalized = {
|
|
64
|
+
enabled: metrics.enabled ?? true,
|
|
65
|
+
topN: getPositiveIntegerOrDefault(metrics.topN, DEFAULT_TOP_N),
|
|
66
|
+
minDurationMs: getNonNegativeNumberOrDefault(metrics.minDurationMs, DEFAULT_MIN_DURATION_MS),
|
|
67
|
+
};
|
|
68
|
+
if (metrics.reporter)
|
|
69
|
+
normalized.reporter = metrics.reporter;
|
|
70
|
+
return normalized;
|
|
71
|
+
};
|
|
72
|
+
export const selectTopSlowestMetrics = (metrics, options) => [...metrics]
|
|
73
|
+
.sort((a, b) => b.durationMs - a.durationMs)
|
|
74
|
+
.slice(0, options.topN);
|
|
75
|
+
export const createMetricsSummary = (metrics, options) => {
|
|
76
|
+
if (!options.enabled || metrics.length === 0)
|
|
77
|
+
return null;
|
|
78
|
+
const topSlowest = selectTopSlowestMetrics(metrics, options);
|
|
79
|
+
if (topSlowest.length === 0)
|
|
80
|
+
return null;
|
|
81
|
+
return {
|
|
82
|
+
totalCaptured: metrics.length,
|
|
83
|
+
totalReported: topSlowest.length,
|
|
84
|
+
topSlowest,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
export const printMetricsSummary = (summary, packageTag) => {
|
|
88
|
+
const lines = summary.topSlowest.map((metric) => ` - ${metric.componentName} in ${metric.file}: ${metric.durationMs.toFixed(2)}ms`);
|
|
89
|
+
console.log(`\n[${packageTag}] Slowest component renders`);
|
|
90
|
+
for (const line of lines)
|
|
91
|
+
console.log(line);
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=plugin-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-metrics.js","sourceRoot":"","sources":["../src/plugin-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type InProcessSetupOptions = {
|
|
2
|
+
isolation: string | undefined;
|
|
3
|
+
runtime: string;
|
|
4
|
+
runtimeOptionArgs: string[];
|
|
5
|
+
domSetupPath: string;
|
|
6
|
+
packageTag: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const setupInProcessEnvironment: (options: InProcessSetupOptions) => Promise<(() => void) | undefined>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { pathToFileURL } from 'node:url';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
import { canHandleRuntime, isNodeRuntime } from "./plugin-command.js";
|
|
12
|
+
const TSX_LOADER_MODULE = 'tsx/esm/api';
|
|
13
|
+
const appendMissingRuntimeArgs = (runtimeOptionArgs) => {
|
|
14
|
+
for (const arg of runtimeOptionArgs) {
|
|
15
|
+
if (process.argv.includes(arg))
|
|
16
|
+
continue;
|
|
17
|
+
process.argv.push(arg);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const loadDomSetupModule = async (domSetupPath) => {
|
|
21
|
+
await import(__rewriteRelativeImportExtension(pathToFileURL(domSetupPath).href));
|
|
22
|
+
};
|
|
23
|
+
const registerNodeTsxLoader = async (packageTag) => {
|
|
24
|
+
const requireFromCwd = createRequire(`${process.cwd()}/`);
|
|
25
|
+
try {
|
|
26
|
+
const resolvedModulePath = requireFromCwd.resolve(TSX_LOADER_MODULE);
|
|
27
|
+
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(resolvedModulePath).href)));
|
|
28
|
+
if (typeof mod.register !== 'function') {
|
|
29
|
+
throw new Error('Missing register() export from tsx loader API');
|
|
30
|
+
}
|
|
31
|
+
return mod.register();
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`[${packageTag}] isolation "none" in Node.js requires a working "tsx" installation to load .tsx/.jsx test files.`, { cause: error });
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
export const setupInProcessEnvironment = async (options) => {
|
|
38
|
+
if (options.isolation !== 'none')
|
|
39
|
+
return undefined;
|
|
40
|
+
if (!canHandleRuntime(options.runtime))
|
|
41
|
+
return undefined;
|
|
42
|
+
let cleanupNodeTsxLoader;
|
|
43
|
+
if (isNodeRuntime(options.runtime)) {
|
|
44
|
+
cleanupNodeTsxLoader = await registerNodeTsxLoader(options.packageTag);
|
|
45
|
+
}
|
|
46
|
+
appendMissingRuntimeArgs(options.runtimeOptionArgs);
|
|
47
|
+
await loadDomSetupModule(options.domSetupPath);
|
|
48
|
+
return cleanupNodeTsxLoader;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=plugin-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-setup.js","sourceRoot":"","sources":["../src/plugin-setup.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMtE,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAExC,MAAM,wBAAwB,GAAG,CAAC,iBAA2B,EAAE,EAAE;IAC/D,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,YAAoB,EAAE,EAAE;IACxD,MAAM,MAAM,kCAAC,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,EAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,UAAkB,EAAE,EAAE;IACzD,MAAM,cAAc,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAE1D,IAAI,CAAC;QACH,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,kCAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC,IAAI,EAAC,CAAoB,CAAC;QACtF,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,IAAI,UAAU,mGAAmG,EACjH,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,EAC5C,OAA8B,EACK,EAAE;IACrC,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACnD,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzD,IAAI,oBAA8C,CAAC;IAEnD,IAAI,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,oBAAoB,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACzE,CAAC;IAED,wBAAwB,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpD,MAAM,kBAAkB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/C,OAAO,oBAAoB,CAAC;AAC9B,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RuntimeOptionArgPrefixes, RuntimeOptions } from './types.ts';
|
|
2
|
+
export declare const createRuntimeOptionArgPrefixes: (base: string) => RuntimeOptionArgPrefixes;
|
|
3
|
+
export declare const parseRuntimeOptions: (prefixes: RuntimeOptionArgPrefixes, argv?: string[]) => RuntimeOptions;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const DEFAULT_DOM_URL = 'http://localhost:3000/';
|
|
2
|
+
const DEFAULT_METRIC_BATCH_SIZE = 50;
|
|
3
|
+
const DEFAULT_METRIC_FLUSH_MS = 50;
|
|
4
|
+
const toNumber = (value) => {
|
|
5
|
+
if (!value)
|
|
6
|
+
return NaN;
|
|
7
|
+
const parsed = Number(value);
|
|
8
|
+
return Number.isFinite(parsed) ? parsed : NaN;
|
|
9
|
+
};
|
|
10
|
+
const findValueByPrefix = (argv, prefix) => {
|
|
11
|
+
const match = argv.find((arg) => arg.startsWith(prefix));
|
|
12
|
+
return match ? match.slice(prefix.length) : undefined;
|
|
13
|
+
};
|
|
14
|
+
const parsePositiveInteger = (value, fallback) => {
|
|
15
|
+
const numeric = toNumber(value);
|
|
16
|
+
if (!Number.isFinite(numeric) || numeric <= 0)
|
|
17
|
+
return fallback;
|
|
18
|
+
return Math.floor(numeric);
|
|
19
|
+
};
|
|
20
|
+
const parseNonNegativeNumber = (value, fallback) => {
|
|
21
|
+
const numeric = toNumber(value);
|
|
22
|
+
if (!Number.isFinite(numeric) || numeric < 0)
|
|
23
|
+
return fallback;
|
|
24
|
+
return numeric;
|
|
25
|
+
};
|
|
26
|
+
export const createRuntimeOptionArgPrefixes = (base) => ({
|
|
27
|
+
metrics: `--${base}-metrics=`,
|
|
28
|
+
minMetricMs: `--${base}-min-metric-ms=`,
|
|
29
|
+
domUrl: `--${base}-dom-url=`,
|
|
30
|
+
metricBatchSize: `--${base}-metric-batch-size=`,
|
|
31
|
+
metricFlushMs: `--${base}-metric-flush-ms=`,
|
|
32
|
+
});
|
|
33
|
+
export const parseRuntimeOptions = (prefixes, argv = process.argv) => {
|
|
34
|
+
const metricsEnabled = findValueByPrefix(argv, prefixes.metrics) === '1' ||
|
|
35
|
+
findValueByPrefix(argv, prefixes.metrics) === 'true';
|
|
36
|
+
const domUrl = findValueByPrefix(argv, prefixes.domUrl)?.trim() || DEFAULT_DOM_URL;
|
|
37
|
+
const minMetricMs = parseNonNegativeNumber(findValueByPrefix(argv, prefixes.minMetricMs), 0);
|
|
38
|
+
const metricBatchSize = parsePositiveInteger(findValueByPrefix(argv, prefixes.metricBatchSize), DEFAULT_METRIC_BATCH_SIZE);
|
|
39
|
+
const metricFlushMs = parsePositiveInteger(findValueByPrefix(argv, prefixes.metricFlushMs), DEFAULT_METRIC_FLUSH_MS);
|
|
40
|
+
return {
|
|
41
|
+
domUrl,
|
|
42
|
+
metricsEnabled,
|
|
43
|
+
minMetricMs,
|
|
44
|
+
metricBatchSize,
|
|
45
|
+
metricFlushMs,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=runtime-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-options.js","sourceRoot":"","sources":["../src/runtime-options.ts"],"names":[],"mappings":"AAKA,MAAM,eAAe,GAAG,wBAAwB,CAAC;AACjD,MAAM,yBAAyB,GAAG,EAAE,CAAC;AACrC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAEnC,MAAM,QAAQ,GAAG,CAAC,KAAyB,EAAE,EAAE;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAC;IACvB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,IAAc,EAAE,MAAc,EAAE,EAAE;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAE,EAAE;IAC3E,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAE,EAAE;IAC7E,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9D,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,IAAY,EACc,EAAE,CAAC,CAAC;IAC9B,OAAO,EAAE,KAAK,IAAI,WAAW;IAC7B,WAAW,EAAE,KAAK,IAAI,iBAAiB;IACvC,MAAM,EAAE,KAAK,IAAI,WAAW;IAC5B,eAAe,EAAE,KAAK,IAAI,qBAAqB;IAC/C,aAAa,EAAE,KAAK,IAAI,mBAAmB;CAC5C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,QAAkC,EAClC,OAAiB,OAAO,CAAC,IAAI,EACb,EAAE;IAClB,MAAM,cAAc,GAClB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,GAAG;QACjD,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC;IAEvD,MAAM,MAAM,GACV,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC;IAEtE,MAAM,WAAW,GAAG,sBAAsB,CACxC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC7C,CAAC,CACF,CAAC;IAEF,MAAM,eAAe,GAAG,oBAAoB,CAC1C,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,EACjD,yBAAyB,CAC1B,CAAC;IAEF,MAAM,aAAa,GAAG,oBAAoB,CACxC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC/C,uBAAuB,CACxB,CAAC;IAEF,OAAO;QACL,MAAM;QACN,cAAc;QACd,WAAW;QACX,eAAe;QACf,aAAa;KACd,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Screen } from '@testing-library/dom';
|
|
2
|
+
import type { RuntimeOptions } from './types.ts';
|
|
3
|
+
export declare const getNow: () => number;
|
|
4
|
+
export type RenderMetricsEmitterOptions = {
|
|
5
|
+
runtimeOptions: RuntimeOptions;
|
|
6
|
+
metricsStateKey: symbol;
|
|
7
|
+
metricsBatchMessageType: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const createRenderMetricsEmitter: (options: RenderMetricsEmitterOptions) => {
|
|
10
|
+
emitRenderMetric: (componentName: string, durationMs: number) => void;
|
|
11
|
+
flushMetricBuffer: () => void;
|
|
12
|
+
clearMetricFlushTimer: () => void;
|
|
13
|
+
};
|
|
14
|
+
export declare const createScreen: () => Screen;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { getQueriesForElement } from '@testing-library/dom';
|
|
2
|
+
export const getNow = typeof performance !== 'undefined' && typeof performance.now === 'function'
|
|
3
|
+
? performance.now.bind(performance)
|
|
4
|
+
: Date.now.bind(Date);
|
|
5
|
+
const getMetricsRuntimeState = (stateKey) => {
|
|
6
|
+
const stateGlobal = globalThis;
|
|
7
|
+
if (!stateGlobal[stateKey]) {
|
|
8
|
+
stateGlobal[stateKey] = {
|
|
9
|
+
metricBuffer: [],
|
|
10
|
+
metricFlushTimer: undefined,
|
|
11
|
+
metricsChannelClosed: false,
|
|
12
|
+
listenersRegistered: false,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return stateGlobal[stateKey];
|
|
16
|
+
};
|
|
17
|
+
export const createRenderMetricsEmitter = (options) => {
|
|
18
|
+
const { runtimeOptions, metricsStateKey, metricsBatchMessageType } = options;
|
|
19
|
+
const metricsState = getMetricsRuntimeState(metricsStateKey);
|
|
20
|
+
const clearMetricFlushTimer = () => {
|
|
21
|
+
if (!metricsState.metricFlushTimer)
|
|
22
|
+
return;
|
|
23
|
+
clearTimeout(metricsState.metricFlushTimer);
|
|
24
|
+
metricsState.metricFlushTimer = undefined;
|
|
25
|
+
};
|
|
26
|
+
const flushMetricBuffer = () => {
|
|
27
|
+
if (!runtimeOptions.metricsEnabled || typeof process.send !== 'function') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (process.connected === false) {
|
|
31
|
+
metricsState.metricBuffer.length = 0;
|
|
32
|
+
metricsState.metricsChannelClosed = true;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (metricsState.metricsChannelClosed ||
|
|
36
|
+
metricsState.metricBuffer.length === 0) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const payload = metricsState.metricBuffer.splice(0, metricsState.metricBuffer.length);
|
|
40
|
+
try {
|
|
41
|
+
process.send({
|
|
42
|
+
type: metricsBatchMessageType,
|
|
43
|
+
metrics: payload,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
metricsState.metricsChannelClosed = true;
|
|
48
|
+
metricsState.metricBuffer.length = 0;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const scheduleMetricFlush = () => {
|
|
52
|
+
if (metricsState.metricFlushTimer)
|
|
53
|
+
return;
|
|
54
|
+
metricsState.metricFlushTimer = setTimeout(() => {
|
|
55
|
+
metricsState.metricFlushTimer = undefined;
|
|
56
|
+
flushMetricBuffer();
|
|
57
|
+
}, runtimeOptions.metricFlushMs);
|
|
58
|
+
metricsState.metricFlushTimer.unref?.();
|
|
59
|
+
};
|
|
60
|
+
if (runtimeOptions.metricsEnabled && !metricsState.listenersRegistered) {
|
|
61
|
+
metricsState.listenersRegistered = true;
|
|
62
|
+
process.on('beforeExit', () => {
|
|
63
|
+
clearMetricFlushTimer();
|
|
64
|
+
flushMetricBuffer();
|
|
65
|
+
});
|
|
66
|
+
process.on('disconnect', () => {
|
|
67
|
+
clearMetricFlushTimer();
|
|
68
|
+
metricsState.metricBuffer.length = 0;
|
|
69
|
+
metricsState.metricsChannelClosed = true;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const emitRenderMetric = (componentName, durationMs) => {
|
|
73
|
+
if (!runtimeOptions.metricsEnabled ||
|
|
74
|
+
typeof process.send !== 'function') {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (process.connected === false || metricsState.metricsChannelClosed) {
|
|
78
|
+
metricsState.metricBuffer.length = 0;
|
|
79
|
+
metricsState.metricsChannelClosed = true;
|
|
80
|
+
clearMetricFlushTimer();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const safeDuration = Number.isFinite(durationMs) && durationMs >= 0 ? durationMs : 0;
|
|
84
|
+
if (safeDuration < runtimeOptions.minMetricMs)
|
|
85
|
+
return;
|
|
86
|
+
metricsState.metricBuffer.push({
|
|
87
|
+
componentName,
|
|
88
|
+
durationMs: safeDuration,
|
|
89
|
+
});
|
|
90
|
+
if (metricsState.metricBuffer.length >= runtimeOptions.metricBatchSize) {
|
|
91
|
+
clearMetricFlushTimer();
|
|
92
|
+
flushMetricBuffer();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
scheduleMetricFlush();
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
emitRenderMetric,
|
|
99
|
+
flushMetricBuffer,
|
|
100
|
+
clearMetricFlushTimer,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
export const createScreen = () => {
|
|
104
|
+
return new Proxy({}, {
|
|
105
|
+
get(_target, prop) {
|
|
106
|
+
const baseScreenQueries = getQueriesForElement(document.body);
|
|
107
|
+
const value = Reflect.get(baseScreenQueries, prop, baseScreenQueries);
|
|
108
|
+
return typeof value === 'function'
|
|
109
|
+
? value.bind(baseScreenQueries)
|
|
110
|
+
: value;
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=testing-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing-core.js","sourceRoot":"","sources":["../src/testing-core.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type DomAdapter = 'happy-dom' | 'jsdom' | {
|
|
2
|
+
setupModule: string;
|
|
3
|
+
};
|
|
4
|
+
export type RenderMetric = {
|
|
5
|
+
file: string;
|
|
6
|
+
componentName: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
};
|
|
9
|
+
export type MetricsSummary = {
|
|
10
|
+
totalCaptured: number;
|
|
11
|
+
totalReported: number;
|
|
12
|
+
topSlowest: RenderMetric[];
|
|
13
|
+
};
|
|
14
|
+
export type MetricsOptions = {
|
|
15
|
+
enabled?: boolean;
|
|
16
|
+
topN?: number;
|
|
17
|
+
minDurationMs?: number;
|
|
18
|
+
reporter?: (summary: MetricsSummary) => void;
|
|
19
|
+
};
|
|
20
|
+
export type TestingPluginOptions = {
|
|
21
|
+
dom?: DomAdapter;
|
|
22
|
+
domUrl?: string;
|
|
23
|
+
metrics?: boolean | MetricsOptions;
|
|
24
|
+
};
|
|
25
|
+
export type NormalizedMetricsOptions = {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
topN: number;
|
|
28
|
+
minDurationMs: number;
|
|
29
|
+
reporter?: (summary: MetricsSummary) => void;
|
|
30
|
+
};
|
|
31
|
+
export type RuntimeOptionArgPrefixes = {
|
|
32
|
+
metrics: string;
|
|
33
|
+
minMetricMs: string;
|
|
34
|
+
domUrl: string;
|
|
35
|
+
metricBatchSize: string;
|
|
36
|
+
metricFlushMs: string;
|
|
37
|
+
};
|
|
38
|
+
export type RuntimeOptions = {
|
|
39
|
+
domUrl: string;
|
|
40
|
+
metricsEnabled: boolean;
|
|
41
|
+
minMetricMs: number;
|
|
42
|
+
metricBatchSize: number;
|
|
43
|
+
metricFlushMs: number;
|
|
44
|
+
};
|
|
45
|
+
export type FrameworkDescriptor = {
|
|
46
|
+
pluginName: string;
|
|
47
|
+
packageTag: string;
|
|
48
|
+
runtimeArgBase: string;
|
|
49
|
+
metricMessageType: string;
|
|
50
|
+
metricBatchMessageType: string;
|
|
51
|
+
testFileExtensions?: string[];
|
|
52
|
+
commandBuilder?: (input: {
|
|
53
|
+
runtime: string;
|
|
54
|
+
command: string[];
|
|
55
|
+
file: string;
|
|
56
|
+
domSetupPath: string;
|
|
57
|
+
runtimeOptionArgs: string[];
|
|
58
|
+
}) => {
|
|
59
|
+
shouldHandle: boolean;
|
|
60
|
+
command: string[];
|
|
61
|
+
};
|
|
62
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,11 +1,90 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pokujs/dom",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"private": false,
|
|
4
5
|
"description": "Shared DOM testing core for Poku framework adapters.",
|
|
5
6
|
"type": "module",
|
|
6
|
-
"main": "./index.js",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20.x.x",
|
|
21
|
+
"bun": ">=1.x.x",
|
|
22
|
+
"deno": ">=2.x.x",
|
|
23
|
+
"typescript": ">=6.x.x"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "npm run test:node",
|
|
27
|
+
"test:node": "node --import=tsx ./node_modules/poku/lib/bin/index.js tests --showLogs",
|
|
28
|
+
"test:bun": "bun ./node_modules/poku/lib/bin/index.js tests --showLogs",
|
|
29
|
+
"test:deno": "deno run -A npm:poku tests --showLogs",
|
|
30
|
+
"clean": "rimraf dist",
|
|
31
|
+
"build": "npm run clean && tsc -p tsconfig.dist.json",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
33
|
+
"lint": "npm run typecheck",
|
|
34
|
+
"check": "npm run typecheck && npm test",
|
|
35
|
+
"prepack": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"poku",
|
|
39
|
+
"dom",
|
|
40
|
+
"testing",
|
|
41
|
+
"happy-dom",
|
|
42
|
+
"jsdom"
|
|
43
|
+
],
|
|
44
|
+
"author": "Lojhan",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/pokujs/dom.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/pokujs/dom#readme",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/pokujs/dom/issues"
|
|
52
|
+
},
|
|
7
53
|
"license": "MIT",
|
|
8
54
|
"publishConfig": {
|
|
9
|
-
"access": "public"
|
|
55
|
+
"access": "public",
|
|
56
|
+
"provenance": true
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@happy-dom/global-registrator": ">=20",
|
|
60
|
+
"happy-dom": ">=20",
|
|
61
|
+
"jsdom": ">=22",
|
|
62
|
+
"poku": ">=4.1.0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@happy-dom/global-registrator": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"happy-dom": {
|
|
69
|
+
"optional": true
|
|
70
|
+
},
|
|
71
|
+
"jsdom": {
|
|
72
|
+
"optional": true
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"@testing-library/dom": "^10.4.1"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@happy-dom/global-registrator": "^20.8.9",
|
|
80
|
+
"@types/jsdom": "^28.0.1",
|
|
81
|
+
"@types/node": "^25.5.0",
|
|
82
|
+
"cross-env": "^10.1.0",
|
|
83
|
+
"happy-dom": "^20.8.9",
|
|
84
|
+
"jsdom": "^26.1.0",
|
|
85
|
+
"poku": "4.2.0",
|
|
86
|
+
"rimraf": "^6.0.1",
|
|
87
|
+
"tsx": "^4.21.0",
|
|
88
|
+
"typescript": "^6.0.2"
|
|
10
89
|
}
|
|
11
90
|
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// placeholder
|