@pwtap/create 0.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.
Files changed (103) hide show
  1. package/core-manifest.json +50 -0
  2. package/dist/commands/add.d.ts +8 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +9 -0
  5. package/dist/commands/add.js.map +1 -0
  6. package/dist/commands/create.d.ts +12 -0
  7. package/dist/commands/create.d.ts.map +1 -0
  8. package/dist/commands/create.js +114 -0
  9. package/dist/commands/create.js.map +1 -0
  10. package/dist/commands/remove.d.ts +7 -0
  11. package/dist/commands/remove.d.ts.map +1 -0
  12. package/dist/commands/remove.js +9 -0
  13. package/dist/commands/remove.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +55 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/injectors/assets.d.ts +6 -0
  19. package/dist/injectors/assets.d.ts.map +1 -0
  20. package/dist/injectors/assets.js +53 -0
  21. package/dist/injectors/assets.js.map +1 -0
  22. package/dist/injectors/envJson.d.ts +6 -0
  23. package/dist/injectors/envJson.d.ts.map +1 -0
  24. package/dist/injectors/envJson.js +39 -0
  25. package/dist/injectors/envJson.js.map +1 -0
  26. package/dist/injectors/fixturesBarrel.d.ts +11 -0
  27. package/dist/injectors/fixturesBarrel.d.ts.map +1 -0
  28. package/dist/injectors/fixturesBarrel.js +66 -0
  29. package/dist/injectors/fixturesBarrel.js.map +1 -0
  30. package/dist/injectors/packageJson.d.ts +6 -0
  31. package/dist/injectors/packageJson.d.ts.map +1 -0
  32. package/dist/injectors/packageJson.js +25 -0
  33. package/dist/injectors/packageJson.js.map +1 -0
  34. package/dist/injectors/pwConfig.d.ts +10 -0
  35. package/dist/injectors/pwConfig.d.ts.map +1 -0
  36. package/dist/injectors/pwConfig.js +40 -0
  37. package/dist/injectors/pwConfig.js.map +1 -0
  38. package/dist/manifest.d.ts +65 -0
  39. package/dist/manifest.d.ts.map +1 -0
  40. package/dist/manifest.js +22 -0
  41. package/dist/manifest.js.map +1 -0
  42. package/dist/plugin-apply.d.ts +13 -0
  43. package/dist/plugin-apply.d.ts.map +1 -0
  44. package/dist/plugin-apply.js +89 -0
  45. package/dist/plugin-apply.js.map +1 -0
  46. package/dist/prompts.d.ts +22 -0
  47. package/dist/prompts.d.ts.map +1 -0
  48. package/dist/prompts.js +65 -0
  49. package/dist/prompts.js.map +1 -0
  50. package/dist/registry.d.ts +26 -0
  51. package/dist/registry.d.ts.map +1 -0
  52. package/dist/registry.js +34 -0
  53. package/dist/registry.js.map +1 -0
  54. package/dist/util/fs.d.ts +13 -0
  55. package/dist/util/fs.d.ts.map +1 -0
  56. package/dist/util/fs.js +32 -0
  57. package/dist/util/fs.js.map +1 -0
  58. package/dist/util/log.d.ts +8 -0
  59. package/dist/util/log.d.ts.map +1 -0
  60. package/dist/util/log.js +9 -0
  61. package/dist/util/log.js.map +1 -0
  62. package/dist/util/markers.d.ts +20 -0
  63. package/dist/util/markers.d.ts.map +1 -0
  64. package/dist/util/markers.js +51 -0
  65. package/dist/util/markers.js.map +1 -0
  66. package/dist/util/run.d.ts +8 -0
  67. package/dist/util/run.d.ts.map +1 -0
  68. package/dist/util/run.js +27 -0
  69. package/dist/util/run.js.map +1 -0
  70. package/package.json +31 -0
  71. package/template/.commitlintrc.json +3 -0
  72. package/template/.prettierrc +17 -0
  73. package/template/api/core/ApiClient.ts +99 -0
  74. package/template/api/core/types.ts +29 -0
  75. package/template/api/index.ts +4 -0
  76. package/template/api/models/pet.ts +24 -0
  77. package/template/api/services/PetService.ts +67 -0
  78. package/template/config/envUtils.ts +70 -0
  79. package/template/config/index.ts +2 -0
  80. package/template/config/loadEnv.ts +110 -0
  81. package/template/env/environments.example.json +20 -0
  82. package/template/eslint.config.js +74 -0
  83. package/template/fixtures/api.ts +46 -0
  84. package/template/fixtures/auth.ts +150 -0
  85. package/template/fixtures/index.ts +38 -0
  86. package/template/fixtures/ui.ts +112 -0
  87. package/template/pages/BasePage.ts +225 -0
  88. package/template/pages/LoginPage.ts +50 -0
  89. package/template/pages/index.ts +2 -0
  90. package/template/playwright.config.ts +71 -0
  91. package/template/templates/gitignore +19 -0
  92. package/template/testData/users.example.json +17 -0
  93. package/template/tests/api/pet.api.ts +60 -0
  94. package/template/tests/example/authSession.spec.ts +34 -0
  95. package/template/tests/example/login.spec.ts +50 -0
  96. package/template/tsconfig.json +33 -0
  97. package/template/utils/apiUtils.ts +224 -0
  98. package/template/utils/dateUtils.ts +158 -0
  99. package/template/utils/index.ts +15 -0
  100. package/template/utils/stringUtils.ts +192 -0
  101. package/template/utils/uiUtils.ts +236 -0
  102. package/template/utils/validationUtils.ts +190 -0
  103. package/template/utils/waitUtils.ts +207 -0
@@ -0,0 +1,50 @@
1
+ {
2
+ "//": "Core manifest — the base package.json scripts + devDependencies @pwtap/create writes into a new project, plus Playwright browsers to install and extra package.json fields. Single source of truth for the core scaffold; plugins add to this via their own manifests. Example: create reads coreManifest.scripts.test → \"playwright test\".",
3
+ "scripts": {
4
+ "test": "playwright test",
5
+ "test:headed": "playwright test --headed",
6
+ "test:debug": "playwright test --debug",
7
+ "test:ui": "playwright test --ui",
8
+ "test:api": "playwright test --project=api",
9
+ "report:playwright": "playwright show-report",
10
+ "codegen": "playwright codegen",
11
+ "lint": "eslint .",
12
+ "lint:fix": "eslint . --fix",
13
+ "format": "prettier --write \"**/*.{ts,js,json,md}\"",
14
+ "type-check": "tsc --noEmit",
15
+ "commit": "cz",
16
+ "prepare": "husky"
17
+ },
18
+ "devDependencies": {
19
+ "@playwright/test": "^1.61.1",
20
+ "@types/node": "^24.13.2",
21
+ "typescript": "^5.9.3",
22
+ "allure-playwright": "^3.10.1",
23
+ "eslint": "^10.5.0",
24
+ "@typescript-eslint/eslint-plugin": "^8.62.0",
25
+ "@typescript-eslint/parser": "^8.62.0",
26
+ "eslint-config-prettier": "^10.1.8",
27
+ "eslint-plugin-playwright": "^2.10.4",
28
+ "eslint-plugin-prettier": "^5.5.6",
29
+ "prettier": "^3.8.4",
30
+ "prettier-plugin-organize-imports": "^4.3.0",
31
+ "husky": "^9.1.7",
32
+ "lint-staged": "^17.0.8",
33
+ "@commitlint/cli": "^21.1.0",
34
+ "@commitlint/config-conventional": "^21.1.0",
35
+ "commitizen": "^4.3.2",
36
+ "cz-conventional-changelog": "^3.3.0"
37
+ },
38
+ "browsers": ["chromium"],
39
+ "packageJson": {
40
+ "config": {
41
+ "commitizen": {
42
+ "path": "cz-conventional-changelog"
43
+ }
44
+ },
45
+ "lint-staged": {
46
+ "*.{ts,tsx,js}": ["eslint --fix", "prettier --write"],
47
+ "*.{json,md}": ["prettier --write"]
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,8 @@
1
+ export interface AddCommandOptions {
2
+ clientDir: string;
3
+ pluginIds: string[];
4
+ install: boolean;
5
+ }
6
+ /** `create-pwtap add <plugin…>` — install and wire one or more plugins into an existing project. */
7
+ export declare function addCommand(opts: AddCommandOptions): Promise<void>;
8
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,oGAAoG;AACpG,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvE"}
@@ -0,0 +1,9 @@
1
+ import { addPlugins } from '../plugin-apply.js';
2
+ /** `create-pwtap add <plugin…>` — install and wire one or more plugins into an existing project. */
3
+ export async function addCommand(opts) {
4
+ if (opts.pluginIds.length === 0) {
5
+ throw new Error('add: name at least one plugin, e.g. `npx create-pwtap add maestro`');
6
+ }
7
+ await addPlugins(opts);
8
+ }
9
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQhD,oGAAoG;AACpG,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAuB;IACtD,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface CreateOptions {
2
+ targetDir: string;
3
+ yes: boolean;
4
+ install: boolean;
5
+ browsers: boolean;
6
+ selectedPluginIds: string[];
7
+ templateDir: string;
8
+ coreManifestPath: string;
9
+ }
10
+ /** Scaffold a new core project (UI + API), then optionally install/inject selected plugins. */
11
+ export declare function createProject(opts: CreateOptions): Promise<void>;
12
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,+FAA+F;AAC/F,wBAAsB,aAAa,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDtE"}
@@ -0,0 +1,114 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { loadCoreManifest } from '../manifest.js';
4
+ import { addPlugins } from '../plugin-apply.js';
5
+ import { Prompter } from '../prompts.js';
6
+ import { KNOWN_PLUGINS } from '../registry.js';
7
+ import { copyDir, exists, isEmptyDir, sortObject, writeJson } from '../util/fs.js';
8
+ import { log } from '../util/log.js';
9
+ import { run } from '../util/run.js';
10
+ /** Scaffold a new core project (UI + API), then optionally install/inject selected plugins. */
11
+ export async function createProject(opts) {
12
+ const { targetDir, templateDir, coreManifestPath } = opts;
13
+ if (!isEmptyDir(targetDir)) {
14
+ throw new Error(`Target directory is not empty: ${targetDir}`);
15
+ }
16
+ fs.mkdirSync(targetDir, { recursive: true });
17
+ log.step(`Scaffolding Playwright Test Automation Platform into ${targetDir}`);
18
+ // 1. Copy the core template verbatim, then reveal the shipped gitignore as .gitignore.
19
+ copyDir(templateDir, targetDir);
20
+ const shippedGitignore = path.join(targetDir, 'templates', 'gitignore');
21
+ if (exists(shippedGitignore)) {
22
+ fs.renameSync(shippedGitignore, path.join(targetDir, '.gitignore'));
23
+ fs.rmSync(path.join(targetDir, 'templates'), { recursive: true, force: true });
24
+ }
25
+ // 2. Gather project name + plugin choices.
26
+ const prompter = new Prompter(opts.yes);
27
+ let name;
28
+ let selectedIds;
29
+ try {
30
+ name = await prompter.text('Project name', path.basename(targetDir));
31
+ selectedIds =
32
+ opts.selectedPluginIds.length > 0
33
+ ? opts.selectedPluginIds
34
+ : await prompter.selectPlugins(KNOWN_PLUGINS);
35
+ }
36
+ finally {
37
+ prompter.close();
38
+ }
39
+ // 3. Write the base package.json from the core manifest.
40
+ writeBasePackageJson(targetDir, name, coreManifestPath);
41
+ // 4. git init + husky hooks so commit hygiene (lint-staged + commitlint) activates on install.
42
+ await initGit(targetDir);
43
+ writeHuskyHooks(targetDir);
44
+ // 5. Install core deps, then plugins (install + inject), then browsers.
45
+ if (opts.install) {
46
+ log.step('Installing dependencies');
47
+ await run('npm', ['install'], { cwd: targetDir });
48
+ }
49
+ if (selectedIds.length > 0) {
50
+ await addPlugins({ clientDir: targetDir, pluginIds: selectedIds, install: opts.install });
51
+ }
52
+ if (opts.browsers) {
53
+ const core = loadCoreManifest(coreManifestPath);
54
+ log.step(`Installing Playwright browsers: ${core.browsers.join(', ')}`);
55
+ await run('npx', ['playwright', 'install', ...core.browsers], { cwd: targetDir }).catch(err => log.warn(`playwright install skipped: ${err instanceof Error ? err.message : String(err)}`));
56
+ }
57
+ printNextSteps(targetDir, name);
58
+ }
59
+ function writeBasePackageJson(targetDir, name, coreManifestPath) {
60
+ const core = loadCoreManifest(coreManifestPath);
61
+ writeJson(path.join(targetDir, 'package.json'), {
62
+ name,
63
+ version: '0.1.0',
64
+ private: true,
65
+ type: 'module',
66
+ scripts: sortObject(core.scripts),
67
+ devDependencies: sortObject(core.devDependencies),
68
+ ...(core.packageJson ?? {}),
69
+ });
70
+ }
71
+ async function initGit(targetDir) {
72
+ // git init so husky's `prepare` can wire hooks during npm install (husky needs a .git dir).
73
+ try {
74
+ await run('git', ['init', '-q'], { cwd: targetDir });
75
+ }
76
+ catch {
77
+ log.warn('git not available — run `git init` later so husky hooks activate.');
78
+ }
79
+ }
80
+ function writeHuskyHooks(targetDir) {
81
+ // Hook files activated by the generated project's `prepare: husky` on install: lint-staged before
82
+ // each commit, commitlint on the message.
83
+ const dir = path.join(targetDir, '.husky');
84
+ fs.mkdirSync(dir, { recursive: true });
85
+ const hooks = {
86
+ 'pre-commit': 'npx lint-staged\n',
87
+ 'commit-msg': 'npx --no -- commitlint --edit "$1"\n',
88
+ };
89
+ for (const [hookName, body] of Object.entries(hooks)) {
90
+ const hookPath = path.join(dir, hookName);
91
+ fs.writeFileSync(hookPath, body);
92
+ try {
93
+ fs.chmodSync(hookPath, 0o755);
94
+ }
95
+ catch {
96
+ // Ignore chmod failures (e.g. on Windows).
97
+ }
98
+ }
99
+ }
100
+ function printNextSteps(targetDir, name) {
101
+ const rel = path.relative(process.cwd(), targetDir) || '.';
102
+ log.done(`Created ${name}`);
103
+ log.info([
104
+ '',
105
+ 'Next steps:',
106
+ ` cd ${rel}`,
107
+ ' cp env/environments.example.json env/environments.json # set BASE_URL / API_BASE_URL',
108
+ ' cp testData/users.example.json testData/users.json # add login sessions (optional)',
109
+ ' npm test # runs chromium + api',
110
+ '',
111
+ 'Add a plugin later: npx create-pwtap add <maestro|appium|...>',
112
+ ].join('\n'));
113
+ }
114
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface RemoveCommandOptions {
2
+ clientDir: string;
3
+ pluginIds: string[];
4
+ }
5
+ /** `create-pwtap remove <plugin…>` — reverse every injection and uninstall the plugin package(s). */
6
+ export declare function removeCommand(opts: RemoveCommandOptions): Promise<void>;
7
+ //# sourceMappingURL=remove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,qGAAqG;AACrG,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7E"}
@@ -0,0 +1,9 @@
1
+ import { removePlugins } from '../plugin-apply.js';
2
+ /** `create-pwtap remove <plugin…>` — reverse every injection and uninstall the plugin package(s). */
3
+ export async function removeCommand(opts) {
4
+ if (opts.pluginIds.length === 0) {
5
+ throw new Error('remove: name at least one plugin, e.g. `npx create-pwtap remove maestro`');
6
+ }
7
+ await removePlugins({ clientDir: opts.clientDir, pluginIds: opts.pluginIds });
8
+ }
9
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAOnD,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA0B;IAC5D,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;IAC9F,CAAC;IACD,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { addCommand } from './commands/add.js';
5
+ import { createProject } from './commands/create.js';
6
+ import { removeCommand } from './commands/remove.js';
7
+ import { KNOWN_PLUGINS } from './registry.js';
8
+ import { log } from './util/log.js';
9
+ // Package root (this file compiles to dist/index.js). template/ and core-manifest.json are bundled
10
+ // alongside dist/ at prepack, so both live at the package root.
11
+ const pkgRoot = fileURLToPath(new URL('..', import.meta.url));
12
+ const templateDir = path.join(pkgRoot, 'template');
13
+ const coreManifestPath = path.join(pkgRoot, 'core-manifest.json');
14
+ /** True if `--flag` is on argv, or npm surfaced it via `npm_config_<flag>` (so `npm init` flags work). */
15
+ function flagPresent(argv, flag) {
16
+ if (argv.includes(flag)) {
17
+ return true;
18
+ }
19
+ const key = `npm_config_${flag.replace(/^--/, '').replace(/-/g, '_')}`;
20
+ const value = process.env[key];
21
+ return value !== undefined && value !== '' && value !== 'false';
22
+ }
23
+ async function main() {
24
+ const argv = process.argv.slice(2);
25
+ const positional = argv.filter(a => !a.startsWith('-'));
26
+ const command = positional[0] === 'add' || positional[0] === 'remove' ? positional[0] : 'create';
27
+ const yes = flagPresent(argv, '--yes') || argv.includes('-y');
28
+ const install = !flagPresent(argv, '--no-install');
29
+ const browsers = !flagPresent(argv, '--no-browsers');
30
+ const pluginIdsFromFlags = KNOWN_PLUGINS.filter(p => flagPresent(argv, p.flag)).map(p => p.id);
31
+ if (command === 'add') {
32
+ const ids = positional.slice(1).length > 0 ? positional.slice(1) : pluginIdsFromFlags;
33
+ await addCommand({ clientDir: process.cwd(), pluginIds: ids, install });
34
+ return;
35
+ }
36
+ if (command === 'remove') {
37
+ await removeCommand({ clientDir: process.cwd(), pluginIds: positional.slice(1) });
38
+ return;
39
+ }
40
+ const targetDir = path.resolve(process.cwd(), positional[0] ?? '.');
41
+ await createProject({
42
+ targetDir,
43
+ yes,
44
+ install,
45
+ browsers,
46
+ selectedPluginIds: pluginIdsFromFlags,
47
+ templateDir,
48
+ coreManifestPath,
49
+ });
50
+ }
51
+ main().catch(err => {
52
+ log.error(err instanceof Error ? err.message : String(err));
53
+ process.exit(1);
54
+ });
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { PluginManifest } from '../manifest.js';
2
+ /** Copy a plugin's example tests/flows into the client once — never overwriting existing files. */
3
+ export declare function copyExamples(clientDir: string, m: PluginManifest): void;
4
+ /** Copy a plugin's docs into the client (e.g. docs/MAESTRO.md). */
5
+ export declare function copyDocs(clientDir: string, m: PluginManifest): void;
6
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/injectors/assets.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA0BrD,mGAAmG;AACnG,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAEvE;AAED,mEAAmE;AACnE,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAEnE"}
@@ -0,0 +1,53 @@
1
+ import { createRequire } from 'node:module';
2
+ import path from 'node:path';
3
+ import { copyDir, ensureDir, exists } from '../util/fs.js';
4
+ /** Absolute root of an installed package, or null when it can't be resolved from the client. */
5
+ function packageRoot(clientDir, pkg) {
6
+ try {
7
+ const require = createRequire(`${clientDir}/`);
8
+ // Resolve the package's main entry (always allowed by "exports"), then walk up to its package.json.
9
+ // Resolving `${pkg}/package.json` directly fails when a package restricts subpaths via "exports".
10
+ let dir = path.dirname(require.resolve(pkg, { paths: [clientDir] }));
11
+ for (let i = 0; i < 8; i++) {
12
+ if (exists(path.join(dir, 'package.json'))) {
13
+ return dir;
14
+ }
15
+ const parent = path.dirname(dir);
16
+ if (parent === dir) {
17
+ break;
18
+ }
19
+ dir = parent;
20
+ }
21
+ return null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /** Copy a plugin's example tests/flows into the client once — never overwriting existing files. */
28
+ export function copyExamples(clientDir, m) {
29
+ copyAssets(clientDir, m, m.examples);
30
+ }
31
+ /** Copy a plugin's docs into the client (e.g. docs/MAESTRO.md). */
32
+ export function copyDocs(clientDir, m) {
33
+ copyAssets(clientDir, m, m.docs);
34
+ }
35
+ function copyAssets(clientDir, m, assets) {
36
+ if (!assets?.length) {
37
+ return;
38
+ }
39
+ const root = packageRoot(clientDir, m.name);
40
+ if (!root) {
41
+ return;
42
+ }
43
+ for (const { src, dest } of assets) {
44
+ const from = path.join(root, src);
45
+ const to = path.join(clientDir, dest);
46
+ if (!exists(from) || exists(to)) {
47
+ continue; // skip missing sources and never overwrite user files
48
+ }
49
+ ensureDir(path.dirname(to));
50
+ copyDir(from, to);
51
+ }
52
+ }
53
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/injectors/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE3D,gGAAgG;AAChG,SAAS,WAAW,CAAC,SAAiB,EAAE,GAAW;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,SAAS,GAAG,CAAC,CAAC;QAC/C,oGAAoG;QACpG,kGAAkG;QAClG,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;QACrE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;gBAC3C,OAAO,GAAG,CAAC;YACb,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM;YACR,CAAC;YACD,GAAG,GAAG,MAAM,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,CAAiB;IAC/D,UAAU,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,CAAiB;IAC3D,UAAU,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CACjB,SAAiB,EACjB,CAAiB,EACjB,MAAwD;IAExD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;IACT,CAAC;IACD,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,MAAM,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,SAAS,CAAC,sDAAsD;QAClE,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { PluginManifest } from '../manifest.js';
2
+ /** Add a plugin's env keys under `common` (loadEnv flattens them into process.env). Skips existing keys. */
3
+ export declare function mergePluginEnv(clientDir: string, m: PluginManifest): void;
4
+ /** Reverse mergePluginEnv: drop the plugin's env keys from `common`. */
5
+ export declare function removePluginEnv(clientDir: string, m: PluginManifest): void;
6
+ //# sourceMappingURL=envJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envJson.d.ts","sourceRoot":"","sources":["../../src/injectors/envJson.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAiBrD,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAczE;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAW1E"}
@@ -0,0 +1,39 @@
1
+ import path from 'node:path';
2
+ import { exists, readJson, writeJson } from '../util/fs.js';
3
+ /** Both env files if present — the tracked example and the gitignored real one. */
4
+ function envFiles(clientDir) {
5
+ return [
6
+ path.join(clientDir, 'env', 'environments.json'),
7
+ path.join(clientDir, 'env', 'environments.example.json'),
8
+ ].filter(exists);
9
+ }
10
+ /** Add a plugin's env keys under `common` (loadEnv flattens them into process.env). Skips existing keys. */
11
+ export function mergePluginEnv(clientDir, m) {
12
+ if (Object.keys(m.envKeys).length === 0) {
13
+ return;
14
+ }
15
+ for (const file of envFiles(clientDir)) {
16
+ const cfg = readJson(file);
17
+ cfg.common = { ...(cfg.common ?? {}) };
18
+ for (const [key, value] of Object.entries(m.envKeys)) {
19
+ if (!(key in cfg.common)) {
20
+ cfg.common[key] = value;
21
+ }
22
+ }
23
+ writeJson(file, cfg);
24
+ }
25
+ }
26
+ /** Reverse mergePluginEnv: drop the plugin's env keys from `common`. */
27
+ export function removePluginEnv(clientDir, m) {
28
+ for (const file of envFiles(clientDir)) {
29
+ const cfg = readJson(file);
30
+ if (!cfg.common) {
31
+ continue;
32
+ }
33
+ for (const key of Object.keys(m.envKeys)) {
34
+ delete cfg.common[key];
35
+ }
36
+ writeJson(file, cfg);
37
+ }
38
+ }
39
+ //# sourceMappingURL=envJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envJson.js","sourceRoot":"","sources":["../../src/injectors/envJson.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAQ5D,mFAAmF;AACnF,SAAS,QAAQ,CAAC,SAAiB;IACjC,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,mBAAmB,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,2BAA2B,CAAC;KACzD,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACnB,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,CAAiB;IACjE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO;IACT,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;QACpC,GAAG,CAAC,MAAM,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC1B,CAAC;QACH,CAAC;QACD,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,CAAiB;IAClE,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,SAAS;QACX,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { PluginManifest } from '../manifest.js';
2
+ /**
3
+ * Splice a plugin's fixture into fixtures/index.ts: its import plus a `mergeTests` arg (if it ships a
4
+ * test object) and/or a `mergeExpects` arg (if it ships matchers). Independent — a matcher-only plugin
5
+ * touches only imports+expects. Returns false if a needed managed marker is missing so the caller can
6
+ * print a paste block instead of half-editing.
7
+ */
8
+ export declare function applyFixture(clientDir: string, m: PluginManifest): boolean;
9
+ /** Reverse applyFixture. */
10
+ export declare function removeFixture(clientDir: string, m: PluginManifest): void;
11
+ //# sourceMappingURL=fixturesBarrel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixturesBarrel.d.ts","sourceRoot":"","sources":["../../src/injectors/fixturesBarrel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAqBrD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAyB1E;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAexE"}
@@ -0,0 +1,66 @@
1
+ import path from 'node:path';
2
+ import { readText, writeText } from '../util/fs.js';
3
+ import { addToRegion, hasRegion, removeFromRegion } from '../util/markers.js';
4
+ function barrelPath(clientDir) {
5
+ return path.join(clientDir, 'fixtures', 'index.ts');
6
+ }
7
+ function importLine(f) {
8
+ const parts = [];
9
+ if (f.test) {
10
+ parts.push(`${f.test.export ?? 'test'} as ${f.test.alias}`);
11
+ }
12
+ if (f.expect) {
13
+ parts.push(`${f.expect.export ?? 'expect'} as ${f.expect.alias}`);
14
+ }
15
+ return `import { ${parts.join(', ')} } from '${f.importFrom}';`;
16
+ }
17
+ /**
18
+ * Splice a plugin's fixture into fixtures/index.ts: its import plus a `mergeTests` arg (if it ships a
19
+ * test object) and/or a `mergeExpects` arg (if it ships matchers). Independent — a matcher-only plugin
20
+ * touches only imports+expects. Returns false if a needed managed marker is missing so the caller can
21
+ * print a paste block instead of half-editing.
22
+ */
23
+ export function applyFixture(clientDir, m) {
24
+ const f = m.fixture;
25
+ if (!f) {
26
+ return true;
27
+ }
28
+ const file = barrelPath(clientDir);
29
+ let src = readText(file);
30
+ if (!hasRegion(src, 'plugins:imports')) {
31
+ return false;
32
+ }
33
+ if (f.test && !hasRegion(src, 'plugins:tests')) {
34
+ return false;
35
+ }
36
+ if (f.expect && !hasRegion(src, 'plugins:expects')) {
37
+ return false;
38
+ }
39
+ src = addToRegion(src, 'plugins:imports', importLine(f), f.importFrom);
40
+ if (f.test) {
41
+ src = addToRegion(src, 'plugins:tests', ` ${f.test.alias},`, `${f.test.alias},`);
42
+ }
43
+ if (f.expect) {
44
+ src = addToRegion(src, 'plugins:expects', ` ${f.expect.alias},`, `${f.expect.alias},`);
45
+ }
46
+ writeText(file, src);
47
+ return true;
48
+ }
49
+ /** Reverse applyFixture. */
50
+ export function removeFixture(clientDir, m) {
51
+ const f = m.fixture;
52
+ if (!f) {
53
+ return;
54
+ }
55
+ const file = barrelPath(clientDir);
56
+ let src = readText(file);
57
+ src = removeFromRegion(src, 'plugins:imports', f.importFrom);
58
+ if (f.test) {
59
+ src = removeFromRegion(src, 'plugins:tests', `${f.test.alias},`);
60
+ }
61
+ if (f.expect) {
62
+ src = removeFromRegion(src, 'plugins:expects', `${f.expect.alias},`);
63
+ }
64
+ writeText(file, src);
65
+ }
66
+ //# sourceMappingURL=fixturesBarrel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixturesBarrel.js","sourceRoot":"","sources":["../../src/injectors/fixturesBarrel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { PluginManifest } from '../manifest.js';
2
+ /** Merge a plugin's scripts + devDependencies into the client package.json (never clobbering user keys wins — plugin values overwrite only same-named keys). */
3
+ export declare function mergePluginPackageJson(clientDir: string, m: PluginManifest): void;
4
+ /** Reverse mergePluginPackageJson: drop the plugin's scripts/devDeps and the plugin package itself. */
5
+ export declare function removePluginPackageJson(clientDir: string, m: PluginManifest): void;
6
+ //# sourceMappingURL=packageJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageJson.d.ts","sourceRoot":"","sources":["../../src/injectors/packageJson.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAUrD,gKAAgK;AAChK,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAMjF;AAED,uGAAuG;AACvG,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAYlF"}
@@ -0,0 +1,25 @@
1
+ import path from 'node:path';
2
+ import { readJson, sortObject, writeJson } from '../util/fs.js';
3
+ /** Merge a plugin's scripts + devDependencies into the client package.json (never clobbering user keys wins — plugin values overwrite only same-named keys). */
4
+ export function mergePluginPackageJson(clientDir, m) {
5
+ const file = path.join(clientDir, 'package.json');
6
+ const pkg = readJson(file);
7
+ pkg.scripts = sortObject({ ...(pkg.scripts ?? {}), ...m.scripts });
8
+ pkg.devDependencies = sortObject({ ...(pkg.devDependencies ?? {}), ...m.devDependencies });
9
+ writeJson(file, pkg);
10
+ }
11
+ /** Reverse mergePluginPackageJson: drop the plugin's scripts/devDeps and the plugin package itself. */
12
+ export function removePluginPackageJson(clientDir, m) {
13
+ const file = path.join(clientDir, 'package.json');
14
+ const pkg = readJson(file);
15
+ for (const key of Object.keys(m.scripts)) {
16
+ delete pkg.scripts?.[key];
17
+ }
18
+ for (const key of Object.keys(m.devDependencies)) {
19
+ delete pkg.devDependencies?.[key];
20
+ }
21
+ delete pkg.devDependencies?.[m.name];
22
+ delete pkg.dependencies?.[m.name];
23
+ writeJson(file, pkg);
24
+ }
25
+ //# sourceMappingURL=packageJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageJson.js","sourceRoot":"","sources":["../../src/injectors/packageJson.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAShE,gKAAgK;AAChK,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,CAAiB;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,QAAQ,CAAc,IAAI,CAAC,CAAC;IACxC,GAAG,CAAC,OAAO,GAAG,UAAU,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,GAAG,CAAC,eAAe,GAAG,UAAU,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3F,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,uBAAuB,CAAC,SAAiB,EAAE,CAAiB;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,QAAQ,CAAc,IAAI,CAAC,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC;QACjD,OAAO,GAAG,CAAC,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { PluginManifest } from '../manifest.js';
2
+ /**
3
+ * Splice a plugin's env gate and project spread into playwright.config.ts. Returns false if a managed
4
+ * marker is missing (caller then prints a paste block). Each project is env-gated so a bare
5
+ * `npm test` stays UI + API only.
6
+ */
7
+ export declare function applyProject(clientDir: string, m: PluginManifest): boolean;
8
+ /** Reverse applyProject (matches on the gate variable name). */
9
+ export declare function removeProject(clientDir: string, m: PluginManifest): void;
10
+ //# sourceMappingURL=pwConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwConfig.d.ts","sourceRoot":"","sources":["../../src/injectors/pwConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQrD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAe1E;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAUxE"}