@stripchatdev/create-stripchat-extension 0.1.46 → 0.1.48

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 (214) hide show
  1. package/dist/bin/cli/actions/updateAction.d.ts +6 -0
  2. package/dist/bin/cli/actions/updateAction.js +33 -0
  3. package/dist/bin/cli/helpers/printCliError.d.ts +1 -0
  4. package/dist/bin/cli/helpers/printCliError.js +21 -0
  5. package/dist/bin/cli/index.js +70 -0
  6. package/dist/bin/create.d.ts +2 -0
  7. package/dist/bin/create.js +246 -0
  8. package/dist/package.json +9 -4
  9. package/dist/src/constants.d.ts +14 -9
  10. package/dist/src/constants.js +73 -12
  11. package/dist/src/dependencies/constants.d.ts +2 -0
  12. package/dist/src/dependencies/constants.js +11 -0
  13. package/dist/src/dependencies/resolveDependencies.d.ts +6 -0
  14. package/dist/src/dependencies/resolveDependencies.js +43 -0
  15. package/dist/src/dependencies/resolveDependencies.test.js +74 -0
  16. package/dist/src/helpers/error.d.ts +3 -0
  17. package/dist/src/helpers/error.js +9 -0
  18. package/dist/src/helpers/error.test.js +15 -0
  19. package/dist/src/helpers/getIsDirectoryExists.d.ts +7 -0
  20. package/dist/src/helpers/getIsDirectoryExists.js +23 -0
  21. package/dist/src/helpers/getIsDirectoryExists.test.js +34 -0
  22. package/dist/src/helpers/getIsJsxFramework.d.ts +2 -0
  23. package/dist/src/helpers/getIsJsxFramework.js +2 -0
  24. package/dist/src/helpers/getIsJsxFramework.test.js +10 -0
  25. package/dist/src/helpers/getIsTypescript.d.ts +2 -0
  26. package/dist/src/helpers/getIsTypescript.js +1 -0
  27. package/dist/src/helpers/getIsTypescript.test.js +10 -0
  28. package/dist/src/helpers/isSubPath.d.ts +1 -0
  29. package/dist/src/helpers/isSubPath.js +5 -0
  30. package/dist/src/helpers/normalizePath.d.ts +2 -0
  31. package/dist/src/helpers/normalizePath.js +4 -0
  32. package/dist/src/helpers/normalizePath.test.js +19 -0
  33. package/dist/src/migrator/executor.d.ts +9 -0
  34. package/dist/src/migrator/executor.js +112 -0
  35. package/dist/src/migrator/migration.d.ts +3 -0
  36. package/dist/src/migrator/migration.js +18 -0
  37. package/dist/src/migrator/migration.test.js +74 -0
  38. package/dist/src/migrator/migrations/migrations.test.js +97 -0
  39. package/dist/src/migrator/migrations/v2/AGENTS_md/001_recreate-with-generated-part.d.ts +2 -0
  40. package/dist/src/migrator/migrations/v2/AGENTS_md/001_recreate-with-generated-part.js +14 -0
  41. package/dist/src/migrator/migrations/v2/_project-config_json/001_create.d.ts +2 -0
  42. package/dist/src/migrator/migrations/v2/_project-config_json/001_create.js +14 -0
  43. package/dist/src/migrator/migrations/v2/vite_config_ts/001_turn_off_minify_and_assets_inline.d.ts +2 -0
  44. package/dist/src/migrator/migrations/v2/vite_config_ts/001_turn_off_minify_and_assets_inline.js +118 -0
  45. package/dist/src/migrator/planner.d.ts +5 -0
  46. package/dist/src/migrator/planner.js +65 -0
  47. package/dist/src/migrator/planner.test.js +40 -0
  48. package/dist/src/migrator/types.d.ts +29 -0
  49. package/dist/src/migrator/updates/updates.test.js +102 -0
  50. package/dist/src/migrator/updates/v2/AGENTS_md/001_update-generated-part.d.ts +2 -0
  51. package/dist/src/migrator/updates/v2/AGENTS_md/001_update-generated-part.js +38 -0
  52. package/dist/src/migrator/updates/v2/package_json/001_update-versions.d.ts +2 -0
  53. package/dist/src/migrator/updates/v2/package_json/001_update-versions.js +77 -0
  54. package/dist/src/migrator/updates/v2/package_json/002_add-cli-commands.d.ts +2 -0
  55. package/dist/src/migrator/updates/v2/package_json/002_add-cli-commands.js +61 -0
  56. package/dist/src/migrator/validators/getIsValidMigration.d.ts +2 -0
  57. package/dist/src/migrator/validators/getIsValidMigration.js +3 -0
  58. package/dist/src/migrator/validators/getIsValidMigration.test.js +13 -0
  59. package/dist/src/projectConfig/buildProjectConfig.d.ts +15 -0
  60. package/dist/src/projectConfig/buildProjectConfig.js +27 -0
  61. package/dist/src/projectConfig/detectPackageManagerRuntime.d.ts +2 -0
  62. package/dist/src/{helpers/detectPackageManager.js → projectConfig/detectPackageManagerRuntime.js} +1 -1
  63. package/dist/src/{helpers/detectPackageManager.test.js → projectConfig/detectPackageManagerRuntime.test.js} +10 -10
  64. package/dist/src/projectConfig/recoverProjectConfig.d.ts +1 -0
  65. package/dist/src/projectConfig/recoverProjectConfig.js +34 -0
  66. package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.d.ts +2 -0
  67. package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.js +16 -0
  68. package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.test.d.ts +1 -0
  69. package/dist/src/projectConfig/recovery/detectPackageManagerFromFiles.test.js +37 -0
  70. package/dist/src/projectConfig/recovery/parseAgentsMd.d.ts +10 -0
  71. package/dist/src/projectConfig/recovery/parseAgentsMd.js +52 -0
  72. package/dist/src/projectConfig/recovery/parseAgentsMd.test.d.ts +1 -0
  73. package/dist/src/projectConfig/recovery/parseAgentsMd.test.js +67 -0
  74. package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.d.ts +1 -0
  75. package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.js +11 -0
  76. package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.test.d.ts +1 -0
  77. package/dist/src/projectConfig/recovery/resolveProjectNameFromDir.test.js +21 -0
  78. package/dist/src/projectConfig/resolveExistsProjectConfig.d.ts +2 -0
  79. package/dist/src/projectConfig/resolveExistsProjectConfig.js +34 -0
  80. package/dist/src/projectConfig/updateProjectConfig.d.ts +2 -0
  81. package/dist/src/projectConfig/updateProjectConfig.js +20 -0
  82. package/dist/src/projectConfig/validators/getIsValidProjectConfig.d.ts +2 -0
  83. package/dist/src/projectConfig/validators/getIsValidProjectConfig.js +6 -0
  84. package/dist/src/projectConfig/validators/getIsValidProjectConfig.test.d.ts +1 -0
  85. package/dist/src/projectConfig/validators/getIsValidProjectConfig.test.js +33 -0
  86. package/dist/src/projectConfig/validators/validateProjectConfig.d.ts +2 -0
  87. package/dist/src/projectConfig/validators/validateProjectConfig.js +30 -0
  88. package/dist/src/projectConfig/validators/validateProjectConfig.test.d.ts +1 -0
  89. package/dist/src/projectConfig/validators/validateProjectConfig.test.js +215 -0
  90. package/dist/src/templater/executor.d.ts +2 -0
  91. package/dist/src/templater/executor.js +22 -0
  92. package/dist/src/templater/executor.test.d.ts +1 -0
  93. package/dist/src/{executor.test.js → templater/executor.test.js} +25 -11
  94. package/dist/src/templater/helpers/getIsTypescriptOnlyFile.d.ts +1 -0
  95. package/dist/src/templater/helpers/getIsTypescriptOnlyFile.js +10 -0
  96. package/dist/src/templater/helpers/getIsTypescriptOnlyFile.test.d.ts +1 -0
  97. package/dist/src/templater/helpers/getIsTypescriptOnlyFile.test.js +25 -0
  98. package/dist/src/templater/helpers/resolveTemplateExtension.d.ts +1 -0
  99. package/dist/src/templater/helpers/resolveTemplateExtension.js +16 -0
  100. package/dist/src/templater/helpers/resolveTemplateExtension.test.d.ts +1 -0
  101. package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.d.ts +1 -1
  102. package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.js +6 -8
  103. package/dist/src/templater/mappers/mapProjectConfigToTemplateModel.test.d.ts +1 -0
  104. package/dist/src/{mappers → templater/mappers}/mapProjectConfigToTemplateModel.test.js +29 -23
  105. package/dist/src/templater/planner.d.ts +2 -0
  106. package/dist/src/templater/planner.js +104 -0
  107. package/dist/src/templater/planner.test.d.ts +1 -0
  108. package/dist/src/templater/planner.test.js +64 -0
  109. package/dist/src/templates/constants.d.ts +6 -0
  110. package/dist/src/templates/constants.js +11 -0
  111. package/dist/src/templates/helpers/resolveTemplatesDir.d.ts +1 -0
  112. package/dist/src/templates/helpers/resolveTemplatesDir.js +16 -0
  113. package/dist/src/templates/templates.d.ts +10 -0
  114. package/dist/src/templates/templates.js +133 -0
  115. package/dist/src/templates/templates.test.d.ts +1 -0
  116. package/dist/src/templates/templates.test.js +263 -0
  117. package/dist/src/templates/types.d.ts +21 -0
  118. package/dist/src/templates/types.js +1 -0
  119. package/dist/src/types.d.ts +28 -9
  120. package/dist/src/validators/getIsValidCategory.d.ts +2 -0
  121. package/dist/src/validators/getIsValidCategory.js +2 -0
  122. package/dist/src/validators/getIsValidCategory.test.d.ts +1 -0
  123. package/dist/src/validators/{isValidCategory.test.js → getIsValidCategory.test.js} +3 -3
  124. package/dist/src/validators/getIsValidFramework.d.ts +2 -0
  125. package/dist/src/validators/getIsValidFramework.js +2 -0
  126. package/dist/src/validators/getIsValidFramework.test.d.ts +1 -0
  127. package/dist/src/validators/{isValidFramework.test.js → getIsValidFramework.test.js} +3 -3
  128. package/dist/src/validators/getIsValidLanguage.d.ts +2 -0
  129. package/dist/src/validators/getIsValidLanguage.js +2 -0
  130. package/dist/src/validators/getIsValidLanguage.test.d.ts +1 -0
  131. package/dist/src/validators/{isValidLanguage.test.js → getIsValidLanguage.test.js} +3 -3
  132. package/dist/src/validators/getIsValidPackageManager.d.ts +2 -0
  133. package/dist/src/validators/getIsValidPackageManager.js +4 -0
  134. package/dist/src/validators/getIsValidPackageManager.test.d.ts +1 -0
  135. package/dist/src/validators/getIsValidPackageManager.test.js +11 -0
  136. package/dist/src/validators/getIsValidSlot.d.ts +2 -0
  137. package/dist/src/validators/getIsValidSlot.js +4 -0
  138. package/dist/src/validators/getIsValidSlot.test.d.ts +1 -0
  139. package/dist/src/validators/getIsValidSlot.test.js +26 -0
  140. package/dist/src/validators/validateSlots.js +40 -8
  141. package/dist/src/validators/validateSlots.test.js +125 -34
  142. package/dist/tsconfig.tsbuildinfo +1 -1
  143. package/package.json +9 -4
  144. package/templates/v1/vite.config.ts.ejs +27 -0
  145. package/templates/v2/.project-config.json.ejs +1 -0
  146. package/templates/v2/AGENTS.md.ejs +712 -0
  147. package/templates/v2/README.md.ejs +31 -0
  148. package/templates/v2/package.json.ejs +26 -0
  149. package/dist/bin/cli.js +0 -221
  150. package/dist/src/executor.d.ts +0 -2
  151. package/dist/src/executor.js +0 -22
  152. package/dist/src/helpers/detectPackageManager.d.ts +0 -2
  153. package/dist/src/helpers/isDirectory.d.ts +0 -1
  154. package/dist/src/helpers/isDirectory.js +0 -9
  155. package/dist/src/helpers/isDirectory.test.js +0 -22
  156. package/dist/src/helpers/isTypescriptOnlyFile.d.ts +0 -1
  157. package/dist/src/helpers/isTypescriptOnlyFile.js +0 -5
  158. package/dist/src/helpers/isTypescriptOnlyFile.test.js +0 -22
  159. package/dist/src/helpers/normalizeRelPath.d.ts +0 -1
  160. package/dist/src/helpers/normalizeRelPath.js +0 -1
  161. package/dist/src/helpers/normalizeRelPath.test.js +0 -19
  162. package/dist/src/helpers/resolveTemplateExtension.d.ts +0 -1
  163. package/dist/src/helpers/resolveTemplateExtension.js +0 -17
  164. package/dist/src/helpers/resolveTemplatesDir.d.ts +0 -1
  165. package/dist/src/helpers/resolveTemplatesDir.js +0 -11
  166. package/dist/src/helpers/resolveTemplatesDir.test.js +0 -21
  167. package/dist/src/planner.d.ts +0 -2
  168. package/dist/src/planner.js +0 -126
  169. package/dist/src/planner.test.js +0 -58
  170. package/dist/src/validators/index.d.ts +0 -6
  171. package/dist/src/validators/index.js +0 -6
  172. package/dist/src/validators/isValidCategory.d.ts +0 -2
  173. package/dist/src/validators/isValidCategory.js +0 -2
  174. package/dist/src/validators/isValidFramework.d.ts +0 -2
  175. package/dist/src/validators/isValidFramework.js +0 -2
  176. package/dist/src/validators/isValidLanguage.d.ts +0 -2
  177. package/dist/src/validators/isValidLanguage.js +0 -2
  178. package/dist/src/validators/validateProjectDir.d.ts +0 -1
  179. package/dist/src/validators/validateProjectDir.js +0 -6
  180. package/dist/src/validators/validateProjectDir.test.js +0 -19
  181. package/dist/bin/{cli.d.ts → cli/index.d.ts} +0 -0
  182. package/dist/src/{executor.test.d.ts → dependencies/resolveDependencies.test.d.ts} +0 -0
  183. package/dist/src/helpers/{detectPackageManager.test.d.ts → error.test.d.ts} +0 -0
  184. package/dist/src/helpers/{isDirectory.test.d.ts → getIsDirectoryExists.test.d.ts} +0 -0
  185. package/dist/src/helpers/{isTypescriptOnlyFile.test.d.ts → getIsJsxFramework.test.d.ts} +0 -0
  186. package/dist/src/helpers/{normalizeRelPath.test.d.ts → getIsTypescript.test.d.ts} +0 -0
  187. package/dist/src/helpers/{resolveTemplateExtension.test.d.ts → normalizePath.test.d.ts} +0 -0
  188. package/dist/src/{helpers/resolveTemplatesDir.test.d.ts → migrator/migration.test.d.ts} +0 -0
  189. package/dist/src/{mappers/mapProjectConfigToTemplateModel.test.d.ts → migrator/migrations/migrations.test.d.ts} +0 -0
  190. package/dist/src/{planner.test.d.ts → migrator/planner.test.d.ts} +0 -0
  191. package/dist/src/{validators/isValidCategory.test.d.ts → migrator/types.js} +0 -0
  192. package/dist/src/{validators/isValidFramework.test.d.ts → migrator/updates/updates.test.d.ts} +0 -0
  193. package/dist/src/{validators/isValidLanguage.test.d.ts → migrator/validators/getIsValidMigration.test.d.ts} +0 -0
  194. package/dist/src/{validators/validateProjectDir.test.d.ts → projectConfig/detectPackageManagerRuntime.test.d.ts} +0 -0
  195. package/dist/src/{helpers → templater/helpers}/resolveTemplateExtension.test.js +0 -0
  196. package/templates/{.gitignore.ejs → v1/.gitignore.ejs} +0 -0
  197. package/templates/{AGENTS.md.ejs → v1/AGENTS.md.ejs} +0 -0
  198. package/templates/{CLAUDE.md → v1/CLAUDE.md} +0 -0
  199. package/templates/{README.md.ejs → v1/README.md.ejs} +0 -0
  200. package/templates/{package.json.ejs → v1/package.json.ejs} +0 -0
  201. package/templates/{public → v1/public}/icon.svg +0 -0
  202. package/templates/{public → v1/public}/manifest.json.ejs +0 -0
  203. package/templates/{public → v1/public}/resolveSlotPage.js.ejs +0 -0
  204. package/templates/{src → v1/src}/slots/background/app.ts.ejs +0 -0
  205. package/templates/{src → v1/src}/slots/background/background.html.ejs +0 -0
  206. package/templates/{src → v1/src}/slots/background/main.ts.ejs +0 -0
  207. package/templates/{src/slots/slot/slot.html.ejs → v1/src/slots/slot/__SLOT_KEY__.html.ejs} +0 -0
  208. package/templates/{src → v1/src}/slots/slot/app.ts.ejs +0 -0
  209. package/templates/{src → v1/src}/slots/slot/app.tsx.ejs +0 -0
  210. package/templates/{src → v1/src}/slots/slot/main.css.ejs +0 -0
  211. package/templates/{src → v1/src}/slots/slot/main.ts.ejs +0 -0
  212. package/templates/{src → v1/src}/slots/slot/main.tsx.ejs +0 -0
  213. package/templates/{tsconfig.json.ejs → v1/tsconfig.json.ejs} +0 -0
  214. package/templates/{vite.config.ts.ejs → v2/vite.config.ts.ejs} +1 -1
@@ -0,0 +1,2 @@
1
+ import type { TLanguage } from '../types.js';
2
+ export declare const getIsValidLanguage: (value: string) => value is TLanguage;
@@ -0,0 +1,2 @@
1
+ import { LANGUAGES } from '../constants.js';
2
+ export const getIsValidLanguage = (value) => LANGUAGES.includes(value);
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,10 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { isValidLanguage } from './isValidLanguage.js';
2
+ import { getIsValidLanguage } from './getIsValidLanguage.js';
3
3
  describe('isValidLanguage', () => {
4
4
  it.each(['ts', 'js'])('returns true for valid language: %s', (lang) => {
5
- expect(isValidLanguage(lang)).toBe(true);
5
+ expect(getIsValidLanguage(lang)).toBe(true);
6
6
  });
7
7
  it.each(['typescript', '', 'TS', 'javascript'])('returns false for invalid language: %s', (lang) => {
8
- expect(isValidLanguage(lang)).toBe(false);
8
+ expect(getIsValidLanguage(lang)).toBe(false);
9
9
  });
10
10
  });
@@ -0,0 +1,2 @@
1
+ import type { TPackageManager } from '../types.js';
2
+ export declare const getIsValidPackageManager: (value: unknown) => value is TPackageManager;
@@ -0,0 +1,4 @@
1
+ import { PACKAGE_MANAGERS } from '../constants.js';
2
+ export const getIsValidPackageManager = (value) => {
3
+ return typeof value === 'string' && PACKAGE_MANAGERS.includes(value);
4
+ };
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { PACKAGE_MANAGERS } from '../constants.js';
3
+ import { getIsValidPackageManager } from './getIsValidPackageManager.js';
4
+ describe('isValidPackageManager', () => {
5
+ it.each(PACKAGE_MANAGERS)('return true if package manager is valid', (packageManager) => {
6
+ expect(getIsValidPackageManager(packageManager)).toBe(true);
7
+ });
8
+ it.each(['some-invalid-page-manager', ''])('return false if package manager is invalid', (packageManager) => {
9
+ expect(getIsValidPackageManager(packageManager)).toBe(false);
10
+ });
11
+ });
@@ -0,0 +1,2 @@
1
+ import type { TSlot } from '../types.js';
2
+ export declare const getIsValidSlot: (value: unknown) => value is TSlot;
@@ -0,0 +1,4 @@
1
+ import { SLOTS } from '../constants.js';
2
+ export const getIsValidSlot = (value) => {
3
+ return typeof value === 'string' && SLOTS.includes(value);
4
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getIsValidSlot } from './getIsValidSlot.js';
3
+ describe('getIsValidSlot', () => {
4
+ it.each([
5
+ 'EXTENSION_SLOT_MAIN_GAME_FUN',
6
+ 'EXTENSION_SLOT_MAIN_SEX_TOY',
7
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
8
+ 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY',
9
+ 'EXTENSION_SLOT_MOVEABLE_OVERLAY',
10
+ 'EXTENSION_SLOT_BACKGROUND',
11
+ ])('returns true for valid slot: %s', (slot) => {
12
+ expect(getIsValidSlot(slot)).toBe(true);
13
+ });
14
+ it.each([
15
+ 'mainGameFun',
16
+ 'EXTENSION_SLOT_MAIN_GAMEFUN',
17
+ 'EXTENSION_SLOT_MOVEABLE_OVERLAY ',
18
+ 'extension_slot_background',
19
+ '',
20
+ ])('returns false for invalid slot string: %s', (slot) => {
21
+ expect(getIsValidSlot(slot)).toBe(false);
22
+ });
23
+ it.each([null, undefined, 1, true, {}, []])('returns false for non-string slot value: %o', (slot) => {
24
+ expect(getIsValidSlot(slot)).toBe(false);
25
+ });
26
+ });
@@ -1,24 +1,43 @@
1
1
  import { SLOT_RULES_BY_CATEGORY } from '../constants.js';
2
+ import { getIsValidSlot } from './getIsValidSlot.js';
2
3
  const formatGroupMessage = (kind, slots) => {
3
- const prefix = kind === 'exactly-one' ? 'Choose exactly one of' : 'Choose at most one of';
4
+ let prefix = '';
5
+ switch (kind) {
6
+ case 'exactly-one':
7
+ prefix = 'Choose exactly one of';
8
+ break;
9
+ case 'at-most-one':
10
+ prefix = 'Choose at most one of';
11
+ break;
12
+ case 'required':
13
+ prefix = 'Missing required slots';
14
+ break;
15
+ }
4
16
  return `${prefix}: ${slots.join(', ')}.`;
5
17
  };
6
18
  export const validateSlots = (slots, category) => {
7
19
  const rules = SLOT_RULES_BY_CATEGORY[category];
8
20
  const allowed = new Set(rules.optional);
9
- const selected = [];
10
- const invalid = [];
21
+ const requiredBase = new Set(rules.requiredBase);
22
+ const selected = new Set();
23
+ const invalid = new Set();
11
24
  for (const slot of slots) {
25
+ if (!getIsValidSlot(slot)) {
26
+ invalid.add(slot);
27
+ continue;
28
+ }
12
29
  if (allowed.has(slot)) {
13
- selected.push(slot);
30
+ selected.add(slot);
31
+ }
32
+ else if (requiredBase.has(slot)) {
33
+ selected.add(slot);
14
34
  }
15
35
  else {
16
- invalid.push(slot);
36
+ invalid.add(slot);
17
37
  }
18
38
  }
19
- const selectedSet = new Set(selected);
20
39
  const violations = rules.groups.flatMap((group) => {
21
- const count = group.slots.filter((slot) => selectedSet.has(slot)).length;
40
+ const count = group.slots.filter((slot) => selected.has(slot)).length;
22
41
  if (group.kind === 'exactly-one' && count !== 1) {
23
42
  return [formatGroupMessage(group.kind, group.slots)];
24
43
  }
@@ -27,5 +46,18 @@ export const validateSlots = (slots, category) => {
27
46
  }
28
47
  return [];
29
48
  });
30
- return { invalid, selected, violations };
49
+ const missingRequiredSlots = [];
50
+ requiredBase.forEach((requiredSlot) => {
51
+ if (!selected.has(requiredSlot)) {
52
+ missingRequiredSlots.push(requiredSlot);
53
+ }
54
+ });
55
+ if (missingRequiredSlots.length) {
56
+ violations.unshift(formatGroupMessage('required', missingRequiredSlots));
57
+ }
58
+ return {
59
+ invalid: Array.from(invalid),
60
+ selected: Array.from(selected),
61
+ violations,
62
+ };
31
63
  };
@@ -1,15 +1,24 @@
1
1
  import { describe, expect, it } from 'vitest';
2
+ import { SLOT_RULES_BY_CATEGORY } from '../constants.js';
2
3
  import { validateSlots } from './validateSlots.js';
3
4
  describe('validateSlots', () => {
4
5
  it('accepts right overlay for games-and-fun', () => {
5
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY'], 'games-and-fun');
6
- expect(result.selected).toEqual(['EXTENSION_SLOT_RIGHT_OVERLAY']);
6
+ const slots = [
7
+ ...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase,
8
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
9
+ ];
10
+ const result = validateSlots(slots, 'games-and-fun');
11
+ expect(result.selected).toEqual(slots);
7
12
  expect(result.invalid).toEqual([]);
8
13
  expect(result.violations).toEqual([]);
9
14
  });
10
15
  it('accepts video decorative overlay for games-and-fun', () => {
11
- const result = validateSlots(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'games-and-fun');
12
- expect(result.selected).toEqual(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
16
+ const slots = [
17
+ ...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase,
18
+ 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY',
19
+ ];
20
+ const result = validateSlots(slots, 'games-and-fun');
21
+ expect(result.selected).toEqual(slots);
13
22
  expect(result.invalid).toEqual([]);
14
23
  expect(result.violations).toEqual([]);
15
24
  });
@@ -18,48 +27,93 @@ describe('validateSlots', () => {
18
27
  expect(result.selected).toEqual([]);
19
28
  expect(result.invalid).toEqual([]);
20
29
  expect(result.violations).toEqual([
30
+ 'Missing required slots: EXTENSION_SLOT_MAIN_GAME_FUN, EXTENSION_SLOT_BACKGROUND.',
31
+ 'Choose exactly one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
32
+ ]);
33
+ });
34
+ it('report about missing required base slots for game-and-fun', () => {
35
+ const result = validateSlots(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'games-and-fun');
36
+ expect(result.selected).toEqual(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
37
+ expect(result.invalid).toEqual([]);
38
+ expect(result.violations).toEqual([
39
+ 'Missing required slots: EXTENSION_SLOT_MAIN_GAME_FUN, EXTENSION_SLOT_BACKGROUND.',
40
+ ]);
41
+ });
42
+ it('report about missing required base and selectable slots for game-and-fun', () => {
43
+ const result = validateSlots([], 'games-and-fun');
44
+ expect(result.selected).toEqual([]);
45
+ expect(result.invalid).toEqual([]);
46
+ expect(result.violations).toEqual([
47
+ 'Missing required slots: EXTENSION_SLOT_MAIN_GAME_FUN, EXTENSION_SLOT_BACKGROUND.',
21
48
  'Choose exactly one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
22
49
  ]);
23
50
  });
24
51
  it('rejects both shared activity overlays for games-and-fun', () => {
25
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY', 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'games-and-fun');
26
- expect(result.selected).toEqual([
52
+ const slots = [
53
+ ...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase,
27
54
  'EXTENSION_SLOT_RIGHT_OVERLAY',
28
55
  'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY',
29
- ]);
56
+ ];
57
+ const result = validateSlots(slots, 'games-and-fun');
58
+ expect(result.selected).toEqual(slots);
30
59
  expect(result.invalid).toEqual([]);
31
60
  expect(result.violations).toEqual([
32
61
  'Choose exactly one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
33
62
  ]);
34
63
  });
35
64
  it('allows sex-toys with no optional slots', () => {
36
- const result = validateSlots([], 'sex-toys');
37
- expect(result.selected).toEqual([]);
65
+ const slots = [
66
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
67
+ ];
68
+ const result = validateSlots(slots, 'sex-toys');
69
+ expect(result.selected).toEqual(slots);
38
70
  expect(result.invalid).toEqual([]);
39
71
  expect(result.violations).toEqual([]);
40
72
  });
41
73
  it('allows moveable overlay for sex-toys', () => {
42
- const result = validateSlots(['EXTENSION_SLOT_MOVEABLE_OVERLAY'], 'sex-toys');
43
- expect(result.selected).toEqual(['EXTENSION_SLOT_MOVEABLE_OVERLAY']);
74
+ const result = validateSlots([...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase, 'EXTENSION_SLOT_MOVEABLE_OVERLAY'], 'sex-toys');
75
+ expect(result.selected).toEqual([
76
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
77
+ 'EXTENSION_SLOT_MOVEABLE_OVERLAY',
78
+ ]);
44
79
  expect(result.invalid).toEqual([]);
45
80
  expect(result.violations).toEqual([]);
46
81
  });
47
82
  it('allows one shared activity overlay for sex-toys', () => {
48
- const result = validateSlots(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'sex-toys');
49
- expect(result.selected).toEqual(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
83
+ const slots = [
84
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
85
+ 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY',
86
+ ];
87
+ const result = validateSlots(slots, 'sex-toys');
88
+ expect(result.selected).toEqual(slots);
50
89
  expect(result.invalid).toEqual([]);
51
90
  expect(result.violations).toEqual([]);
52
91
  });
53
92
  it('allows one shared activity overlay plus moveable overlay for sex-toys', () => {
54
- const result = validateSlots(['EXTENSION_SLOT_MOVEABLE_OVERLAY', 'EXTENSION_SLOT_RIGHT_OVERLAY'], 'sex-toys');
55
- expect(result.selected).toEqual([
93
+ const slots = [
94
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
56
95
  'EXTENSION_SLOT_MOVEABLE_OVERLAY',
57
96
  'EXTENSION_SLOT_RIGHT_OVERLAY',
58
- ]);
97
+ ];
98
+ const result = validateSlots(slots, 'sex-toys');
99
+ expect(result.selected).toEqual(slots);
59
100
  expect(result.invalid).toEqual([]);
60
101
  expect(result.violations).toEqual([]);
61
102
  });
62
103
  it('rejects both shared activity overlays for sex-toys', () => {
104
+ const slots = [
105
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
106
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
107
+ 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY',
108
+ ];
109
+ const result = validateSlots(slots, 'sex-toys');
110
+ expect(result.selected).toEqual(slots);
111
+ expect(result.invalid).toEqual([]);
112
+ expect(result.violations).toEqual([
113
+ 'Choose at most one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
114
+ ]);
115
+ });
116
+ it('reports missing required base slots together with overlay-group violation for sex-toys', () => {
63
117
  const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY', 'EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'sex-toys');
64
118
  expect(result.selected).toEqual([
65
119
  'EXTENSION_SLOT_RIGHT_OVERLAY',
@@ -67,63 +121,100 @@ describe('validateSlots', () => {
67
121
  ]);
68
122
  expect(result.invalid).toEqual([]);
69
123
  expect(result.violations).toEqual([
124
+ 'Missing required slots: EXTENSION_SLOT_MAIN_SEX_TOY, EXTENSION_SLOT_BACKGROUND.',
70
125
  'Choose at most one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
71
126
  ]);
72
127
  });
73
128
  it('reports invalid slot names separately from rule violations', () => {
74
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY', 'unknown-slot'], 'games-and-fun');
75
- expect(result.selected).toEqual(['EXTENSION_SLOT_RIGHT_OVERLAY']);
129
+ const result = validateSlots([
130
+ ...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase,
131
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
132
+ 'unknown-slot',
133
+ ], 'games-and-fun');
134
+ expect(result.selected).toEqual([
135
+ ...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase,
136
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
137
+ ]);
76
138
  expect(result.invalid).toEqual(['unknown-slot']);
77
139
  expect(result.violations).toEqual([]);
78
140
  });
79
141
  it('rejects all optional slots for chat-bots', () => {
80
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY'], 'chat-bots');
81
- expect(result.selected).toEqual([]);
142
+ const result = validateSlots([...SLOT_RULES_BY_CATEGORY['chat-bots'].requiredBase, 'EXTENSION_SLOT_RIGHT_OVERLAY'], 'chat-bots');
143
+ expect(result.selected).toEqual(SLOT_RULES_BY_CATEGORY['chat-bots'].requiredBase);
82
144
  expect(result.invalid).toEqual(['EXTENSION_SLOT_RIGHT_OVERLAY']);
83
145
  expect(result.violations).toEqual([]);
84
146
  });
85
- it('returns empty result for empty input on category with no selectable slots', () => {
147
+ it('reports missing required slots for empty input on category with no selectable slots', () => {
86
148
  const result = validateSlots([], 'chat-bots');
87
149
  expect(result.selected).toEqual([]);
88
150
  expect(result.invalid).toEqual([]);
89
- expect(result.violations).toEqual([]);
151
+ expect(result.violations).toEqual([
152
+ 'Missing required slots: EXTENSION_SLOT_BACKGROUND.',
153
+ ]);
90
154
  });
91
155
  it('allows broadcast-tools with no optional slots', () => {
92
- const result = validateSlots([], 'broadcast-tools');
93
- expect(result.selected).toEqual([]);
156
+ const slots = [
157
+ ...SLOT_RULES_BY_CATEGORY['broadcast-tools'].requiredBase,
158
+ ];
159
+ const result = validateSlots(slots, 'broadcast-tools');
160
+ expect(result.selected).toEqual(slots);
94
161
  expect(result.invalid).toEqual([]);
95
162
  expect(result.violations).toEqual([]);
96
163
  });
97
164
  it('allows moveable overlay for broadcast-tools', () => {
98
- const result = validateSlots(['EXTENSION_SLOT_MOVEABLE_OVERLAY'], 'broadcast-tools');
99
- expect(result.selected).toEqual(['EXTENSION_SLOT_MOVEABLE_OVERLAY']);
165
+ const slots = [
166
+ ...SLOT_RULES_BY_CATEGORY['broadcast-tools'].requiredBase,
167
+ 'EXTENSION_SLOT_MOVEABLE_OVERLAY',
168
+ ];
169
+ const result = validateSlots(slots, 'broadcast-tools');
170
+ expect(result.selected).toEqual(slots);
100
171
  expect(result.invalid).toEqual([]);
101
172
  expect(result.violations).toEqual([]);
102
173
  });
103
174
  it('rejects unsupported optional slots for broadcast-tools', () => {
104
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY'], 'broadcast-tools');
105
- expect(result.selected).toEqual([]);
175
+ const slots = [
176
+ 'EXTENSION_SLOT_BACKGROUND',
177
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
178
+ ];
179
+ const result = validateSlots(slots, 'broadcast-tools');
180
+ expect(result.selected).toEqual(['EXTENSION_SLOT_BACKGROUND']);
106
181
  expect(result.invalid).toEqual(['EXTENSION_SLOT_RIGHT_OVERLAY']);
107
182
  expect(result.violations).toEqual([]);
108
183
  });
109
184
  it('filters invalid slot names while preserving valid selections', () => {
110
- const result = validateSlots(['EXTENSION_SLOT_RIGHT_OVERLAY', 'nonExistent', 'alsoWrong'], 'sex-toys');
111
- expect(result.selected).toEqual(['EXTENSION_SLOT_RIGHT_OVERLAY']);
185
+ const result = validateSlots([
186
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
187
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
188
+ 'nonExistent',
189
+ 'alsoWrong',
190
+ ], 'sex-toys');
191
+ expect(result.selected).toEqual([
192
+ ...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase,
193
+ 'EXTENSION_SLOT_RIGHT_OVERLAY',
194
+ ]);
112
195
  expect(result.invalid).toEqual(['nonExistent', 'alsoWrong']);
113
196
  expect(result.violations).toEqual([]);
114
197
  });
115
198
  it('rejects alias-like slot names that are not slot constants', () => {
116
- const result = validateSlots(['moveableOverlay'], 'games-and-fun');
117
- expect(result.selected).toEqual([]);
199
+ const result = validateSlots([...SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase, 'moveableOverlay'], 'games-and-fun');
200
+ expect(result.selected).toEqual(SLOT_RULES_BY_CATEGORY['games-and-fun'].requiredBase);
118
201
  expect(result.invalid).toEqual(['moveableOverlay']);
119
202
  expect(result.violations).toEqual([
120
203
  'Choose exactly one of: EXTENSION_SLOT_RIGHT_OVERLAY, EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY.',
121
204
  ]);
122
205
  });
123
206
  it('handles all invalid slots', () => {
124
- const result = validateSlots(['unknown1', 'unknown2'], 'sex-toys');
125
- expect(result.selected).toEqual([]);
207
+ const result = validateSlots([...SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase, 'unknown1', 'unknown2'], 'sex-toys');
208
+ expect(result.selected).toEqual(SLOT_RULES_BY_CATEGORY['sex-toys'].requiredBase);
126
209
  expect(result.invalid).toEqual(['unknown1', 'unknown2']);
127
210
  expect(result.violations).toEqual([]);
128
211
  });
212
+ it('report about missing required slots for game-and-fun', () => {
213
+ const result = validateSlots(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY'], 'games-and-fun');
214
+ expect(result.selected).toEqual(['EXTENSION_SLOT_VIDEO_DECORATIVE_OVERLAY']);
215
+ expect(result.invalid).toEqual([]);
216
+ expect(result.violations).toEqual([
217
+ 'Missing required slots: EXTENSION_SLOT_MAIN_GAME_FUN, EXTENSION_SLOT_BACKGROUND.',
218
+ ]);
219
+ });
129
220
  });