@playcraft/devkit 1.0.31-beta.11 → 1.0.31-beta.12

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 (95) hide show
  1. package/cli/bin/playable-scripts.js +6 -53
  2. package/cli/commands/build.js +32 -241
  3. package/cli/commands/builds.js +2 -13
  4. package/cli/commands/dev.js +1 -22
  5. package/cli/commands/pack.js +40 -320
  6. package/cli/commands/vite-dev.js +1 -7
  7. package/core/artifacts/emit-fonts.test.js +1 -0
  8. package/core/artifacts/emit.js +4 -98
  9. package/core/artifacts/fflate.js +1 -31
  10. package/core/artifacts/zip.js +1 -39
  11. package/core/batch-build.js +147 -1261
  12. package/core/constants.js +2 -20
  13. package/core/cos-uploader.js +23 -289
  14. package/core/engines/cocos/clean-cache.js +5 -179
  15. package/core/engines/cocos/clean-cache.test.js +1 -75
  16. package/core/engines/cocos/cli-build.js +2 -116
  17. package/core/engines/cocos/cli.js +11 -38
  18. package/core/engines/cocos/constants.js +1 -21
  19. package/core/engines/cocos/creator-cli.js +1 -108
  20. package/core/engines/cocos/dev-server.js +4 -412
  21. package/core/engines/cocos/fs.js +1 -105
  22. package/core/engines/cocos/injects/3x/init.js +19 -438
  23. package/core/engines/cocos/injects/3x/main.js +2 -52
  24. package/core/engines/cocos/injects/libs/pako.js +1 -2
  25. package/core/engines/cocos/mcp-refresh.js +2 -76
  26. package/core/engines/cocos/merge.js +3 -148
  27. package/core/engines/cocos/pack.js +1 -187
  28. package/core/engines/cocos/preview-cache.js +2 -48
  29. package/core/engines/cocos/preview-cache.test.js +1 -32
  30. package/core/engines/cocos/preview-concat.js +5 -189
  31. package/core/engines/cocos/preview-concat.test.js +1 -73
  32. package/core/engines/cocos/preview-json-hook.js +1 -200
  33. package/core/engines/cocos/preview-json-pack.js +3 -376
  34. package/core/engines/cocos/preview-json-pack.test.js +2 -226
  35. package/core/engines/cocos/preview-proxy.js +1 -132
  36. package/core/engines/cocos/rebundle-preview.js +2 -54
  37. package/core/engines/cocos/strip-social-share.js +3 -115
  38. package/core/engines/cocos/theme-assets.js +2 -161
  39. package/core/engines/cocos/writable-cli.js +2 -248
  40. package/core/engines/cocos/writable-cli.test.js +1 -112
  41. package/core/engines/web/index.js +1 -20
  42. package/core/engines/web/vite.dev.js +17 -322
  43. package/core/engines/web/webpack.build.js +37 -522
  44. package/core/engines/web/webpack.common.js +11 -177
  45. package/core/engines/web/webpack.dev.js +6 -88
  46. package/core/index.js +7 -101
  47. package/core/injectors/apply.js +1 -94
  48. package/core/injectors/check-channel-matrix.js +2 -130
  49. package/core/injectors/spec.js +9 -217
  50. package/core/loaders/gltf-loader.js +28 -74
  51. package/core/options.js +16 -353
  52. package/core/plugins/AdikteevInjectorPlugin.js +4 -26
  53. package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
  54. package/core/plugins/DAPIInjectorPlugin.js +2 -25
  55. package/core/plugins/DebuggerInjectionPlugin.js +3 -31
  56. package/core/plugins/ExitAPIInjectorPlugin.js +3 -56
  57. package/core/plugins/FflateCompressionPlugin.js +40 -231
  58. package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
  59. package/core/plugins/LiftoffInjectorPlugin.js +4 -26
  60. package/core/plugins/MRAIDInjectorPlugin.js +2 -24
  61. package/core/plugins/MintegralInjectorPlugin.js +2 -25
  62. package/core/plugins/PangleInjectorPlugin.js +2 -24
  63. package/core/plugins/PlaycraftOrientationInjectorPlugin.js +3 -29
  64. package/core/plugins/SnapchatInjectorPlugin.js +4 -26
  65. package/core/plugins/SocialMediaInjectorPlugin.js +7 -119
  66. package/core/plugins/TikTokInjectorPlugin.js +2 -24
  67. package/core/plugins/UnityInjectorPlugin.js +8 -37
  68. package/core/plugins/ZipPlugin.js +20 -154
  69. package/core/plugins/socialMediaVitePlugin.js +2 -108
  70. package/core/utils/buildDefines.js +2 -30
  71. package/core/utils/buildTemplateString.js +5 -39
  72. package/core/utils/date.js +1 -16
  73. package/core/utils/fontRegistry.js +13 -81
  74. package/core/utils/fontResolver.js +37 -335
  75. package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +7 -42
  76. package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
  77. package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
  78. package/core/utils/getPlaycraftOrientationSuffix.js +2 -9
  79. package/core/utils/injectSDKPlugins.js +13 -68
  80. package/core/utils/logOptions.js +5 -46
  81. package/core/utils/mergeOptions.js +2 -21
  82. package/core/utils/obfuscateLevels.js +10 -0
  83. package/core/utils/obfuscateLevels.test.js +10 -0
  84. package/core/utils/parseArgvOptions.js +5 -125
  85. package/core/utils/resolveChannelFold2Zip.js +3 -15
  86. package/core/utils/validateThemeData.js +26 -227
  87. package/core/validators/pre-build-checker.js +25 -287
  88. package/core/validators/tracking-validator.js +40 -441
  89. package/core/validators/tracking-validator.test.js +2 -84
  90. package/core/vite.dev.js +1 -1
  91. package/core/webpack.build.js +1 -1
  92. package/core/webpack.common.js +1 -1
  93. package/core/webpack.dev.js +1 -1
  94. package/package.json +2 -3
  95. package/README.md +0 -262
@@ -1,10 +1,6 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- // ============================================================
1
+ "use strict";const fs=require("fs");const path=require("path");// ============================================================
5
2
  // 埋点方法配置
6
3
  // ============================================================
7
-
8
4
  /**
9
5
  * 埋点方法配置
10
6
  * @typedef {Object} TrackingMethod
@@ -12,212 +8,31 @@ const path = require('path');
12
8
  * @property {boolean} required - 是否必须调用
13
9
  * @property {string} description - 方法描述
14
10
  * @property {string[]} channels - 对应的渠道埋点
15
- */
16
-
17
- /**
11
+ *//**
18
12
  * 所有埋点方法配置
19
13
  * @type {TrackingMethod[]}
20
- */
21
- const TRACKING_METHODS = [
22
- {
23
- name: 'onPlaycraftTrackingInit',
24
- required: true,
25
- description: 'SDK 初始化开始',
26
- channels: ['Bigabid:mraid_viewable', 'InMobi:Ad_Load_Start', 'AppLovin:LOADING']
27
- },
28
- {
29
- name: 'onPlaycraftTrackingLoading',
30
- required: true,
31
- description: '游戏资源加载中',
32
- channels: ['Bigabid:game_viewable', 'InMobi:Ad_Viewable', 'AppLovin:LOADED']
33
- },
34
- {
35
- name: 'onPlaycraftTrackingLoaded',
36
- required: true,
37
- description: '主场景就绪,用户可交互',
38
- channels: ['AppLovin:DISPLAYED']
39
- },
40
- {
41
- name: 'onPlaycraftChallengeStart',
42
- required: true,
43
- description: '挑战开始(首次用户交互)',
44
- channels: ['Bigabid:engagement', 'InMobi:First_Engagement', 'AppLovin:CHALLENGE_STARTED']
45
- },
46
- {
47
- name: 'onPlaycraftChallengeProgress',
48
- required: false,
49
- description: '进度百分比追踪(可选)',
50
- channels: ['AppLovin:CHALLENGE_PASS_*']
51
- },
52
- {
53
- name: 'onPlaycraftChallengeSuccess',
54
- required: true,
55
- description: '游戏挑战成功',
56
- channels: ['AppLovin:CHALLENGE_SOLVED', 'Bigabid:complete', 'InMobi:Gameplay_Complete']
57
- },
58
- {
59
- name: 'onPlaycraftChallengeFinish',
60
- required: false,
61
- description: '游戏结束(可选)',
62
- channels: ['Bigabid:complete', 'InMobi:Gameplay_Complete', 'AppLovin:ENDCARD_SHOWN']
63
- },
64
- {
65
- name: 'onPlaycraftInstall',
66
- required: true,
67
- description: '点击安装',
68
- channels: ['Bigabid:click', 'InMobi:DSP_Click', 'AppLovin:CTA_CLICKED']
69
- },
70
- {
71
- name: 'onPlaycraftRetry',
72
- required: false,
73
- description: '重试游戏(可选)',
74
- channels: ['AppLovin:CHALLENGE_RETRY']
75
- },
76
- {
77
- name: 'onPlaycraftChallengeFailed',
78
- required: true,
79
- description: '游戏挑战失败',
80
- channels: ['AppLovin:CHALLENGE_FAILED']
81
- }
82
- ];
83
-
84
- /**
14
+ */const TRACKING_METHODS=[{name:"onPlaycraftTrackingInit",required:true,description:"SDK \u521D\u59CB\u5316\u5F00\u59CB",channels:["Bigabid:mraid_viewable","InMobi:Ad_Load_Start","AppLovin:LOADING"]},{name:"onPlaycraftTrackingLoading",required:true,description:"\u6E38\u620F\u8D44\u6E90\u52A0\u8F7D\u4E2D",channels:["Bigabid:game_viewable","InMobi:Ad_Viewable","AppLovin:LOADED"]},{name:"onPlaycraftTrackingLoaded",required:true,description:"\u4E3B\u573A\u666F\u5C31\u7EEA\uFF0C\u7528\u6237\u53EF\u4EA4\u4E92",channels:["AppLovin:DISPLAYED"]},{name:"onPlaycraftChallengeStart",required:true,description:"\u6311\u6218\u5F00\u59CB\uFF08\u9996\u6B21\u7528\u6237\u4EA4\u4E92\uFF09",channels:["Bigabid:engagement","InMobi:First_Engagement","AppLovin:CHALLENGE_STARTED"]},{name:"onPlaycraftChallengeProgress",required:false,description:"\u8FDB\u5EA6\u767E\u5206\u6BD4\u8FFD\u8E2A\uFF08\u53EF\u9009\uFF09",channels:["AppLovin:CHALLENGE_PASS_*"]},{name:"onPlaycraftChallengeSuccess",required:true,description:"\u6E38\u620F\u6311\u6218\u6210\u529F",channels:["AppLovin:CHALLENGE_SOLVED","Bigabid:complete","InMobi:Gameplay_Complete"]},{name:"onPlaycraftChallengeFinish",required:false,description:"\u6E38\u620F\u7ED3\u675F\uFF08\u53EF\u9009\uFF09",channels:["Bigabid:complete","InMobi:Gameplay_Complete","AppLovin:ENDCARD_SHOWN"]},{name:"onPlaycraftInstall",required:true,description:"\u70B9\u51FB\u5B89\u88C5",channels:["Bigabid:click","InMobi:DSP_Click","AppLovin:CTA_CLICKED"]},{name:"onPlaycraftRetry",required:false,description:"\u91CD\u8BD5\u6E38\u620F\uFF08\u53EF\u9009\uFF09",channels:["AppLovin:CHALLENGE_RETRY"]},{name:"onPlaycraftChallengeFailed",required:true,description:"\u6E38\u620F\u6311\u6218\u5931\u8D25",channels:["AppLovin:CHALLENGE_FAILED"]}];/**
85
15
  * SDK 静态方法映射到 tracking 方法
86
16
  * 这些 SDK 方法内部会调用对应的 tracking 方法
87
- */
88
- const SDK_TO_TRACKING_MAP = {
89
- 'playcraftInit': 'onPlaycraftTrackingInit',
90
- 'playcraftStart': 'onPlaycraftTrackingLoading',
91
- 'playcraftInteractive': 'onPlaycraftTrackingLoaded',
92
- 'playcraftChallengeStart': 'onPlaycraftChallengeStart',
93
- 'recordPlaycraftChallengeProgress': 'onPlaycraftChallengeProgress',
94
- 'playcraftRecordSuccess': 'onPlaycraftChallengeSuccess',
95
- 'playcraftFinish': 'onPlaycraftChallengeFinish',
96
- 'playcraftInstall': 'onPlaycraftInstall',
97
- 'playcraftRetry': 'onPlaycraftRetry',
98
- 'playcraftRecordFailed': 'onPlaycraftChallengeFailed'
99
- };
100
-
101
- /** Phaser / Three 游戏逻辑在 src;Cocos 在 assets/scripts。不要扫 library/temp。 */
102
- const ENGINE_SCAN_ROOTS = {
103
- cocos: ['assets/scripts'],
104
- phaser: ['src'],
105
- threejs: ['src'],
106
- };
107
-
108
- const DEFAULT_EXCLUDE_DIRS = [
109
- 'node_modules', 'dist', 'build', '.git', '.claude',
110
- 'library', 'temp', 'profiles', 'native', 'local', 'dist-all',
111
- ];
112
-
113
- function detectProjectEngine(projectRoot, explicit) {
114
- if (explicit) return String(explicit).toLowerCase();
115
- try {
116
- const configPath = path.join(projectRoot, 'builds.config.js');
117
- if (fs.existsSync(configPath)) {
118
- delete require.cache[require.resolve(configPath)];
119
- const cfg = require(configPath);
120
- if (cfg && cfg.engine) return String(cfg.engine).toLowerCase();
121
- }
122
- } catch {
123
- // ignore invalid builds.config.js
124
- }
125
- if (fs.existsSync(path.join(projectRoot, 'settings/cocos.config.json'))) return 'cocos';
126
- if (
127
- fs.existsSync(path.join(projectRoot, 'assets/scripts')) &&
128
- fs.existsSync(path.join(projectRoot, 'assets/scenes'))
129
- ) {
130
- return 'cocos';
131
- }
132
- return '';
133
- }
134
-
135
- function resolveScanRoots(projectRoot, engine) {
136
- const rels = ENGINE_SCAN_ROOTS[engine] || ENGINE_SCAN_ROOTS.phaser;
137
- const roots = rels
138
- .map((rel) => path.join(projectRoot, rel))
139
- .filter((dir) => fs.existsSync(dir));
140
- return roots.length ? roots : [projectRoot];
141
- }
142
-
143
- function toRelScanRoots(projectRoot, roots) {
144
- return roots.map((dir) => {
145
- const rel = path.relative(projectRoot, dir);
146
- return rel || '.';
147
- });
148
- }
149
-
150
- // ============================================================
17
+ */const SDK_TO_TRACKING_MAP={"playcraftInit":"onPlaycraftTrackingInit","playcraftStart":"onPlaycraftTrackingLoading","playcraftInteractive":"onPlaycraftTrackingLoaded","playcraftChallengeStart":"onPlaycraftChallengeStart","recordPlaycraftChallengeProgress":"onPlaycraftChallengeProgress","playcraftRecordSuccess":"onPlaycraftChallengeSuccess","playcraftFinish":"onPlaycraftChallengeFinish","playcraftInstall":"onPlaycraftInstall","playcraftRetry":"onPlaycraftRetry","playcraftRecordFailed":"onPlaycraftChallengeFailed"};/** Phaser / Three 游戏逻辑在 src;Cocos 在 assets/scripts。不要扫 library/temp。 */const ENGINE_SCAN_ROOTS={cocos:["assets/scripts"],phaser:["src"],threejs:["src"]};const DEFAULT_EXCLUDE_DIRS=["node_modules","dist","build",".git",".claude","library","temp","profiles","native","local","dist-all"];function detectProjectEngine(projectRoot,explicit){if(explicit)return String(explicit).toLowerCase();try{const configPath=path.join(projectRoot,"builds.config.js");if(fs.existsSync(configPath)){delete require.cache[require.resolve(configPath)];const cfg=require(configPath);if(cfg&&cfg.engine)return String(cfg.engine).toLowerCase()}}catch{// ignore invalid builds.config.js
18
+ }if(fs.existsSync(path.join(projectRoot,"settings/cocos.config.json")))return"cocos";if(fs.existsSync(path.join(projectRoot,"assets/scripts"))&&fs.existsSync(path.join(projectRoot,"assets/scenes"))){return"cocos"}return""}function resolveScanRoots(projectRoot,engine){const rels=ENGINE_SCAN_ROOTS[engine]||ENGINE_SCAN_ROOTS.phaser;const roots=rels.map(rel=>path.join(projectRoot,rel)).filter(dir=>fs.existsSync(dir));return roots.length?roots:[projectRoot]}function toRelScanRoots(projectRoot,roots){return roots.map(dir=>{const rel=path.relative(projectRoot,dir);return rel||"."})}// ============================================================
151
19
  // 文件扫描工具
152
20
  // ============================================================
153
-
154
21
  /**
155
22
  * 递归扫描目录获取所有源码文件
156
23
  * @param {string} dir - 目录路径
157
24
  * @param {string[]} extensions - 文件扩展名列表
158
25
  * @param {string[]} excludeDirs - 排除的目录名列表
159
26
  * @returns {string[]} 文件路径列表
160
- */
161
- function scanSourceFiles(dir, extensions = ['.ts', '.tsx', '.js', '.jsx'], excludeDirs = DEFAULT_EXCLUDE_DIRS) {
162
- const files = [];
163
-
164
- function scan(currentDir) {
165
- if (!fs.existsSync(currentDir)) return;
166
-
167
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
168
-
169
- for (const entry of entries) {
170
- const fullPath = path.join(currentDir, entry.name);
171
-
172
- if (entry.isDirectory()) {
173
- // 跳过排除的目录
174
- if (excludeDirs.includes(entry.name)) continue;
175
- scan(fullPath);
176
- } else if (entry.isFile()) {
177
- // 检查文件扩展名
178
- const ext = path.extname(entry.name);
179
- if (extensions.includes(ext)) {
180
- files.push(fullPath);
181
- }
182
- }
183
- }
184
- }
185
-
186
- scan(dir);
187
- return files;
188
- }
189
-
190
- function scanSourceFilesFromRoots(roots, extensions, excludeDirs) {
191
- const files = [];
192
- const seen = new Set();
193
- for (const root of roots) {
194
- for (const file of scanSourceFiles(root, extensions, excludeDirs)) {
195
- if (seen.has(file)) continue;
196
- seen.add(file);
197
- files.push(file);
198
- }
199
- }
200
- return files;
201
- }
202
-
203
- /**
27
+ */function scanSourceFiles(dir,extensions=[".ts",".tsx",".js",".jsx"],excludeDirs=DEFAULT_EXCLUDE_DIRS){const files=[];function scan(currentDir){if(!fs.existsSync(currentDir))return;const entries=fs.readdirSync(currentDir,{withFileTypes:true});for(const entry of entries){const fullPath=path.join(currentDir,entry.name);if(entry.isDirectory()){// 跳过排除的目录
28
+ if(excludeDirs.includes(entry.name))continue;scan(fullPath)}else if(entry.isFile()){// 检查文件扩展名
29
+ const ext=path.extname(entry.name);if(extensions.includes(ext)){files.push(fullPath)}}}}scan(dir);return files}function scanSourceFilesFromRoots(roots,extensions,excludeDirs){const files=[];const seen=new Set;for(const root of roots){for(const file of scanSourceFiles(root,extensions,excludeDirs)){if(seen.has(file))continue;seen.add(file);files.push(file)}}return files}/**
204
30
  * 读取文件内容(带错误处理)
205
31
  * @param {string} filePath - 文件路径
206
32
  * @returns {string|null} 文件内容或 null
207
- */
208
- function readFileContent(filePath) {
209
- try {
210
- return fs.readFileSync(filePath, 'utf-8');
211
- } catch (err) {
212
- console.warn(`[警告] 无法读取文件: ${filePath}`, err.message);
213
- return null;
214
- }
215
- }
216
-
217
- // ============================================================
33
+ */function readFileContent(filePath){try{return fs.readFileSync(filePath,"utf-8")}catch(err){console.warn(`[警告] 无法读取文件: ${filePath}`,err.message);return null}}// ============================================================
218
34
  // 方法调用检测
219
35
  // ============================================================
220
-
221
36
  /**
222
37
  * 检测代码中是否包含 tracking 方法的直接调用
223
38
  * @param {string} content - 文件内容
@@ -226,21 +41,10 @@ function readFileContent(filePath) {
226
41
  *
227
42
  * 注意:不依赖对象名称,只检测方法调用模式
228
43
  * 匹配:xxx.onPlaycraftXxx( 或 xxx['onPlaycraftXxx']( 或 xxx["onPlaycraftXxx"](
229
- */
230
- function detectDirectTrackingCall(content, methodName) {
231
- const patterns = [
232
- // 匹配 .方法名(
233
- new RegExp(`\\.${methodName}\\s*\\(`),
234
- // 匹配 ['方法名'](
235
- new RegExp(`\\['${methodName}'\\]\\s*\\(`),
236
- // 匹配 ["方法名"](
237
- new RegExp(`\\["${methodName}"\\]\\s*\\(`)
238
- ];
239
-
240
- return patterns.some(pattern => pattern.test(content));
241
- }
242
-
243
- /**
44
+ */function detectDirectTrackingCall(content,methodName){const patterns=[// 匹配 .方法名(
45
+ new RegExp(`\\.${methodName}\\s*\\(`),// 匹配 ['方法名'](
46
+ new RegExp(`\\['${methodName}'\\]\\s*\\(`),// 匹配 ["方法名"](
47
+ new RegExp(`\\["${methodName}"\\]\\s*\\(`)];return patterns.some(pattern=>pattern.test(content))}/**
244
48
  * 检测代码中是否包含 SDK 方法调用(会间接触发 tracking)
245
49
  * @param {string} content - 文件内容
246
50
  * @param {string} sdkMethod - SDK 方法名
@@ -248,48 +52,18 @@ function detectDirectTrackingCall(content, methodName) {
248
52
  *
249
53
  * 注意:不依赖对象名称,只检测方法调用模式
250
54
  * 匹配:xxx.playcraftXxx( 或 xxx['playcraftXxx']( 或 xxx["playcraftXxx"](
251
- */
252
- function detectSDKCall(content, sdkMethod) {
253
- const patterns = [
254
- // 匹配 .方法名(
255
- new RegExp(`\\.${sdkMethod}\\s*\\(`),
256
- // 匹配 ['方法名'](
257
- new RegExp(`\\['${sdkMethod}'\\]\\s*\\(`),
258
- // 匹配 ["方法名"](
259
- new RegExp(`\\["${sdkMethod}"\\]\\s*\\(`)
260
- ];
261
-
262
- return patterns.some(pattern => pattern.test(content));
263
- }
264
-
265
- /**
55
+ */function detectSDKCall(content,sdkMethod){const patterns=[// 匹配 .方法名(
56
+ new RegExp(`\\.${sdkMethod}\\s*\\(`),// 匹配 ['方法名'](
57
+ new RegExp(`\\['${sdkMethod}'\\]\\s*\\(`),// 匹配 ["方法名"](
58
+ new RegExp(`\\["${sdkMethod}"\\]\\s*\\(`)];return patterns.some(pattern=>pattern.test(content))}/**
266
59
  * 检测是否导入了 @playcraft/ads-tracking
267
60
  * @param {string} content - 文件内容
268
61
  * @returns {boolean} 是否导入了 tracking
269
- */
270
- function hasTrackingImport(content) {
271
- return /from\s+['"]@playcraft\/ads-tracking(?:\/[^'"]*)?['"]/.test(content) ||
272
- /require\s*\(\s*['"]@playcraft\/ads-tracking(?:\/[^'"]*)?['"]\s*\)/.test(content);
273
- }
274
-
275
- /**
62
+ */function hasTrackingImport(content){return /from\s+['"]@playcraft\/ads-tracking(?:\/[^'"]*)?['"]/.test(content)||/require\s*\(\s*['"]@playcraft\/ads-tracking(?:\/[^'"]*)?['"]\s*\)/.test(content)}/**
276
63
  * 检测是否导入了 @playcraft/adsdk(含 /cjs 等子路径,以及项目内 playcraft-adsdk 封装)
277
- */
278
- function hasSDKImport(content) {
279
- return /from\s+['"]@playcraft\/adsdk(?:\/[^'"]*)?['"]/.test(content) ||
280
- /require\s*\(\s*['"]@playcraft\/adsdk(?:\/[^'"]*)?['"]\s*\)/.test(content) ||
281
- /from\s+['"][^'"]*playcraft-adsdk['"]/.test(content) ||
282
- /require\s*\(\s*['"][^'"]*playcraft-adsdk['"]\s*\)/.test(content);
283
- }
284
-
285
- function hasAnySdkTrackingCall(content) {
286
- return Object.keys(SDK_TO_TRACKING_MAP).some((sdkMethod) => detectSDKCall(content, sdkMethod));
287
- }
288
-
289
- // ============================================================
64
+ */function hasSDKImport(content){return /from\s+['"]@playcraft\/adsdk(?:\/[^'"]*)?['"]/.test(content)||/require\s*\(\s*['"]@playcraft\/adsdk(?:\/[^'"]*)?['"]\s*\)/.test(content)||/from\s+['"][^'"]*playcraft-adsdk['"]/.test(content)||/require\s*\(\s*['"][^'"]*playcraft-adsdk['"]\s*\)/.test(content)}function hasAnySdkTrackingCall(content){return Object.keys(SDK_TO_TRACKING_MAP).some(sdkMethod=>detectSDKCall(content,sdkMethod))}// ============================================================
290
65
  // 验证核心逻辑
291
66
  // ============================================================
292
-
293
67
  /**
294
68
  * 验证结果
295
69
  * @typedef {Object} ValidationResult
@@ -299,9 +73,7 @@ function hasAnySdkTrackingCall(content) {
299
73
  * @property {string[]} errors - 错误信息列表
300
74
  * @property {string[]} warnings - 警告信息列表
301
75
  * @property {Object} stats - 统计信息
302
- */
303
-
304
- /**
76
+ *//**
305
77
  * 验证项目中的埋点调用
306
78
  * @param {string} projectRoot - 项目根目录
307
79
  * @param {Object} [options] - 验证选项
@@ -311,204 +83,31 @@ function hasAnySdkTrackingCall(content) {
311
83
  * @param {string[]} [options.scanDirs] - 覆盖默认扫描目录(相对项目根)
312
84
  * @param {boolean} [options.verbose] - 是否输出详细信息
313
85
  * @returns {ValidationResult} 验证结果
314
- */
315
- function validateTracking(projectRoot, options = {}) {
316
- const {
317
- extensions = ['.ts', '.tsx', '.js', '.jsx'],
318
- excludeDirs = DEFAULT_EXCLUDE_DIRS,
319
- verbose = false
320
- } = options;
321
- const engine = detectProjectEngine(projectRoot, options.engine);
322
- const scanRoots = Array.isArray(options.scanDirs) && options.scanDirs.length
323
- ? options.scanDirs.map((dir) => path.resolve(projectRoot, dir)).filter((dir) => fs.existsSync(dir))
324
- : resolveScanRoots(projectRoot, engine);
325
-
326
- const result = {
327
- success: false,
328
- integrationType: 'none',
329
- methods: [],
330
- errors: [],
331
- warnings: [],
332
- stats: {
333
- totalFiles: 0,
334
- scannedFiles: 0,
335
- hasTrackingImport: false,
336
- hasSDKImport: false,
337
- engine,
338
- scanRoots: toRelScanRoots(projectRoot, scanRoots),
339
- }
340
- };
341
-
342
- // 1. 按引擎扫描源码目录,避免 Cocos library/temp 把检测带偏
343
- if (verbose) {
344
- console.log(`\n[扫描] 项目: ${projectRoot}`);
345
- console.log(`[扫描] 引擎: ${engine || '(default/src)'}`);
346
- console.log(`[扫描] 目录: ${result.stats.scanRoots.join(', ')}`);
347
- }
348
- const files = scanSourceFilesFromRoots(scanRoots, extensions, excludeDirs);
349
- result.stats.totalFiles = files.length;
350
-
351
- if (files.length === 0) {
352
- result.errors.push('未找到任何源码文件');
353
- return result;
354
- }
355
-
356
- if (verbose) console.log(`[扫描] 找到 ${files.length} 个源码文件\n`);
357
-
358
- // 2. 读取所有文件内容并合并(用于全局检测)
359
- let allContent = '';
360
- for (const file of files) {
361
- const content = readFileContent(file);
362
- if (content) {
363
- allContent += content + '\n';
364
- result.stats.scannedFiles++;
365
- }
366
- }
367
-
368
- // 3. 判断集成类型
369
- result.stats.hasTrackingImport = hasTrackingImport(allContent);
370
- result.stats.hasSDKImport = hasSDKImport(allContent);
371
-
372
- if (result.stats.hasSDKImport || hasAnySdkTrackingCall(allContent)) {
373
- result.integrationType = 'sdk';
374
- } else if (result.stats.hasTrackingImport) {
375
- result.integrationType = 'tracking';
376
- } else {
377
- result.errors.push('未检测到 @playcraft/adsdk 或 @playcraft/ads-tracking 的导入');
378
- return result;
379
- }
380
-
381
- if (verbose) {
382
- console.log(`[集成类型] ${result.integrationType === 'sdk' ? 'SDK 集成(通过 sdk 静态方法调用)' : '直接 tracking 集成'}`);
383
- console.log(`[导入检测] SDK: ${result.stats.hasSDKImport ? '✓' : '✗'} | Tracking: ${result.stats.hasTrackingImport ? '✓' : '✗'}\n`);
384
- }
385
-
386
- // 4. 检测每个埋点方法
387
- for (const method of TRACKING_METHODS) {
388
- let found = false;
389
-
390
- if (result.integrationType === 'sdk') {
391
- // SDK 集成:检测 SDK 方法调用
392
- const sdkMethod = Object.keys(SDK_TO_TRACKING_MAP).find(
393
- key => SDK_TO_TRACKING_MAP[key] === method.name
394
- );
395
- if (sdkMethod) {
396
- found = detectSDKCall(allContent, sdkMethod);
397
- }
398
- } else if (result.integrationType === 'tracking') {
399
- // 直接 tracking 集成:检测 tracking 方法调用
400
- found = detectDirectTrackingCall(allContent, method.name);
401
- }
402
-
403
- result.methods.push({
404
- method: method.name,
405
- found,
406
- required: method.required,
407
- description: method.description
408
- });
409
-
410
- // 必须方法未找到 -> 错误
411
- if (method.required && !found) {
412
- result.errors.push(`❌ 缺少必须的埋点方法: ${method.name} (${method.description})`);
413
- }
414
-
415
- // 可选方法未找到 -> 警告
416
- if (!method.required && !found) {
417
- result.warnings.push(`⚠️ 未找到可选埋点方法: ${method.name} (${method.description})`);
418
- }
419
- }
420
-
421
- // 5. 判断验证结果
422
- result.success = result.errors.length === 0;
423
-
424
- return result;
425
- }
426
-
427
- // ============================================================
86
+ */function validateTracking(projectRoot,options={}){const{extensions=[".ts",".tsx",".js",".jsx"],excludeDirs=DEFAULT_EXCLUDE_DIRS,verbose=false}=options;const engine=detectProjectEngine(projectRoot,options.engine);const scanRoots=Array.isArray(options.scanDirs)&&options.scanDirs.length?options.scanDirs.map(dir=>path.resolve(projectRoot,dir)).filter(dir=>fs.existsSync(dir)):resolveScanRoots(projectRoot,engine);const result={success:false,integrationType:"none",methods:[],errors:[],warnings:[],stats:{totalFiles:0,scannedFiles:0,hasTrackingImport:false,hasSDKImport:false,engine,scanRoots:toRelScanRoots(projectRoot,scanRoots)}};// 1. 按引擎扫描源码目录,避免 Cocos library/temp 把检测带偏
87
+ if(verbose){console.log(`\n[扫描] 项目: ${projectRoot}`);console.log(`[扫描] 引擎: ${engine||"(default/src)"}`);console.log(`[扫描] 目录: ${result.stats.scanRoots.join(", ")}`)}const files=scanSourceFilesFromRoots(scanRoots,extensions,excludeDirs);result.stats.totalFiles=files.length;if(files.length===0){result.errors.push("\u672A\u627E\u5230\u4EFB\u4F55\u6E90\u7801\u6587\u4EF6");return result}if(verbose)console.log(`[扫描] 找到 ${files.length} 个源码文件\n`);// 2. 读取所有文件内容并合并(用于全局检测)
88
+ let allContent="";for(const file of files){const content=readFileContent(file);if(content){allContent+=content+"\n";result.stats.scannedFiles++}}// 3. 判断集成类型
89
+ result.stats.hasTrackingImport=hasTrackingImport(allContent);result.stats.hasSDKImport=hasSDKImport(allContent);if(result.stats.hasSDKImport||hasAnySdkTrackingCall(allContent)){result.integrationType="sdk"}else if(result.stats.hasTrackingImport){result.integrationType="tracking"}else{result.errors.push("\u672A\u68C0\u6D4B\u5230 @playcraft/adsdk \u6216 @playcraft/ads-tracking \u7684\u5BFC\u5165");return result}if(verbose){console.log(`[集成类型] ${result.integrationType==="sdk"?"SDK \u96C6\u6210\uFF08\u901A\u8FC7 sdk \u9759\u6001\u65B9\u6CD5\u8C03\u7528\uFF09":"\u76F4\u63A5 tracking \u96C6\u6210"}`);console.log(`[导入检测] SDK: ${result.stats.hasSDKImport?"\u2713":"\u2717"} | Tracking: ${result.stats.hasTrackingImport?"\u2713":"\u2717"}\n`)}// 4. 检测每个埋点方法
90
+ for(const method of TRACKING_METHODS){let found=false;if(result.integrationType==="sdk"){// SDK 集成:检测 SDK 方法调用
91
+ const sdkMethod=Object.keys(SDK_TO_TRACKING_MAP).find(key=>SDK_TO_TRACKING_MAP[key]===method.name);if(sdkMethod){found=detectSDKCall(allContent,sdkMethod)}}else if(result.integrationType==="tracking"){// 直接 tracking 集成:检测 tracking 方法调用
92
+ found=detectDirectTrackingCall(allContent,method.name)}result.methods.push({method:method.name,found,required:method.required,description:method.description});// 必须方法未找到 -> 错误
93
+ if(method.required&&!found){result.errors.push(`❌ 缺少必须的埋点方法: ${method.name} (${method.description})`)}// 可选方法未找到 -> 警告
94
+ if(!method.required&&!found){result.warnings.push(`⚠️ 未找到可选埋点方法: ${method.name} (${method.description})`)}}// 5. 判断验证结果
95
+ result.success=result.errors.length===0;return result}// ============================================================
428
96
  // 格式化输出
429
97
  // ============================================================
430
-
431
98
  /**
432
99
  * 格式化验证结果并输出到控制台
433
100
  * @param {ValidationResult} result - 验证结果
434
101
  * @param {boolean} [showDetails=true] - 是否显示详细信息
435
- */
436
- function printValidationResult(result, showDetails = true) {
437
- console.log('\n' + '='.repeat(60));
438
- console.log('📊 埋点验证报告');
439
- console.log('='.repeat(60));
440
-
441
- // 统计信息
442
- console.log(`\n📁 文件统计: 扫描 ${result.stats.scannedFiles}/${result.stats.totalFiles} 个文件`);
443
- if (result.stats.engine || (result.stats.scanRoots && result.stats.scanRoots.length)) {
444
- console.log(`🧭 引擎: ${result.stats.engine || 'default'} | 目录: ${(result.stats.scanRoots || []).join(', ') || '.'}`);
445
- }
446
- console.log(`🔗 集成类型: ${result.integrationType === 'sdk' ? 'SDK 集成' : result.integrationType === 'tracking' ? 'Tracking 直接集成' : '未检测到'}`);
447
-
448
- // 方法检测结果
449
- if (showDetails) {
450
- console.log('\n📋 方法检测明细:');
451
- console.log('-'.repeat(60));
452
-
453
- const requiredMethods = result.methods.filter(m => m.required);
454
- const optionalMethods = result.methods.filter(m => !m.required);
455
-
456
- console.log('\n必须方法:');
457
- for (const m of requiredMethods) {
458
- const status = m.found ? '✅' : '❌';
459
- console.log(` ${status} ${m.method.padEnd(35)} ${m.found ? '已调用' : '未调用'}`);
460
- }
461
-
462
- console.log('\n可选方法:');
463
- for (const m of optionalMethods) {
464
- const status = m.found ? '✅' : '⚠️ ';
465
- console.log(` ${status} ${m.method.padEnd(35)} ${m.found ? '已调用' : '未调用'}`);
466
- }
467
- }
468
-
469
- // 错误信息
470
- if (result.errors.length > 0) {
471
- console.log('\n❌ 错误:');
472
- result.errors.forEach(err => console.log(` ${err}`));
473
- }
474
-
475
- // 警告信息
476
- if (result.warnings.length > 0) {
477
- console.log('\n⚠️ 警告:');
478
- result.warnings.forEach(warn => console.log(` ${warn}`));
479
- }
480
-
481
- // 最终结果
482
- console.log('\n' + '='.repeat(60));
483
- if (result.success) {
484
- console.log('✅ 验证通过!所有必须的埋点方法都已正确调用。');
485
- } else {
486
- console.log('❌ 验证失败!存在缺失的必须埋点方法,请检查代码。');
487
- }
488
- console.log('='.repeat(60) + '\n');
489
- }
490
-
491
- // ============================================================
102
+ */function printValidationResult(result,showDetails=true){console.log("\n"+"=".repeat(60));console.log("\uD83D\uDCCA \u57CB\u70B9\u9A8C\u8BC1\u62A5\u544A");console.log("=".repeat(60));// 统计信息
103
+ console.log(`\n📁 文件统计: 扫描 ${result.stats.scannedFiles}/${result.stats.totalFiles} 个文件`);if(result.stats.engine||result.stats.scanRoots&&result.stats.scanRoots.length){console.log(`🧭 引擎: ${result.stats.engine||"default"} | 目录: ${(result.stats.scanRoots||[]).join(", ")||"."}`)}console.log(`🔗 集成类型: ${result.integrationType==="sdk"?"SDK \u96C6\u6210":result.integrationType==="tracking"?"Tracking \u76F4\u63A5\u96C6\u6210":"\u672A\u68C0\u6D4B\u5230"}`);// 方法检测结果
104
+ if(showDetails){console.log("\n\uD83D\uDCCB \u65B9\u6CD5\u68C0\u6D4B\u660E\u7EC6:");console.log("-".repeat(60));const requiredMethods=result.methods.filter(m=>m.required);const optionalMethods=result.methods.filter(m=>!m.required);console.log("\n\u5FC5\u987B\u65B9\u6CD5:");for(const m of requiredMethods){const status=m.found?"\u2705":"\u274C";console.log(` ${status} ${m.method.padEnd(35)} ${m.found?"\u5DF2\u8C03\u7528":"\u672A\u8C03\u7528"}`)}console.log("\n\u53EF\u9009\u65B9\u6CD5:");for(const m of optionalMethods){const status=m.found?"\u2705":"\u26A0\uFE0F ";console.log(` ${status} ${m.method.padEnd(35)} ${m.found?"\u5DF2\u8C03\u7528":"\u672A\u8C03\u7528"}`)}}// 错误信息
105
+ if(result.errors.length>0){console.log("\n\u274C \u9519\u8BEF:");result.errors.forEach(err=>console.log(` ${err}`))}// 警告信息
106
+ if(result.warnings.length>0){console.log("\n\u26A0\uFE0F \u8B66\u544A:");result.warnings.forEach(warn=>console.log(` ${warn}`))}// 最终结果
107
+ console.log("\n"+"=".repeat(60));if(result.success){console.log("\u2705 \u9A8C\u8BC1\u901A\u8FC7\uFF01\u6240\u6709\u5FC5\u987B\u7684\u57CB\u70B9\u65B9\u6CD5\u90FD\u5DF2\u6B63\u786E\u8C03\u7528\u3002")}else{console.log("\u274C \u9A8C\u8BC1\u5931\u8D25\uFF01\u5B58\u5728\u7F3A\u5931\u7684\u5FC5\u987B\u57CB\u70B9\u65B9\u6CD5\uFF0C\u8BF7\u68C0\u67E5\u4EE3\u7801\u3002")}console.log("=".repeat(60)+"\n")}// ============================================================
492
108
  // 导出
493
109
  // ============================================================
494
-
495
- module.exports = {
496
- // 核心验证函数
497
- validateTracking,
498
- printValidationResult,
499
-
500
- // 配置数据(供外部使用)
501
- TRACKING_METHODS,
502
- SDK_TO_TRACKING_MAP,
503
- ENGINE_SCAN_ROOTS,
504
- DEFAULT_EXCLUDE_DIRS,
505
-
506
- // 工具函数(供外部使用)
507
- detectProjectEngine,
508
- resolveScanRoots,
509
- scanSourceFiles,
510
- detectDirectTrackingCall,
511
- detectSDKCall,
512
- hasTrackingImport,
513
- hasSDKImport
514
- };
110
+ module.exports={// 核心验证函数
111
+ validateTracking,printValidationResult,// 配置数据(供外部使用)
112
+ TRACKING_METHODS,SDK_TO_TRACKING_MAP,ENGINE_SCAN_ROOTS,DEFAULT_EXCLUDE_DIRS,// 工具函数(供外部使用)
113
+ detectProjectEngine,resolveScanRoots,scanSourceFiles,detectDirectTrackingCall,detectSDKCall,hasTrackingImport,hasSDKImport};
@@ -1,18 +1,4 @@
1
- 'use strict';
2
-
3
- const { describe, it, before, after } = require('node:test');
4
- const assert = require('node:assert/strict');
5
- const fs = require('fs');
6
- const os = require('os');
7
- const path = require('path');
8
- const {
9
- validateTracking,
10
- detectProjectEngine,
11
- resolveScanRoots,
12
- hasSDKImport,
13
- } = require('./tracking-validator.js');
14
-
15
- const SDK_SOURCE = `
1
+ "use strict";const{describe,it,before,after}=require("node:test");const assert=require("node:assert/strict");const fs=require("fs");const os=require("os");const path=require("path");const{validateTracking,detectProjectEngine,resolveScanRoots,hasSDKImport}=require("./tracking-validator.js");const SDK_SOURCE=`
16
2
  import { sdk } from '@playcraft/adsdk/cjs';
17
3
  sdk.playcraftInit(() => {});
18
4
  sdk.playcraftStart();
@@ -21,72 +7,4 @@ sdk.playcraftChallengeStart();
21
7
  sdk.playcraftRecordSuccess();
22
8
  sdk.playcraftRecordFailed();
23
9
  sdk.playcraftInstall();
24
- `;
25
-
26
- describe('tracking validator engine scan roots', () => {
27
- let root;
28
-
29
- before(() => {
30
- root = fs.mkdtempSync(path.join(os.tmpdir(), 'tracking-scan-'));
31
- fs.mkdirSync(path.join(root, 'assets/scripts/game'), { recursive: true });
32
- fs.mkdirSync(path.join(root, 'assets/scenes'), { recursive: true });
33
- fs.mkdirSync(path.join(root, 'library/import'), { recursive: true });
34
- fs.mkdirSync(path.join(root, 'src'), { recursive: true });
35
- fs.writeFileSync(path.join(root, 'builds.config.js'), "module.exports = { engine: 'cocos' };\n");
36
- fs.writeFileSync(path.join(root, 'assets/scripts/game/GameRoot.ts'), SDK_SOURCE);
37
- fs.writeFileSync(
38
- path.join(root, 'library/import/noise.js'),
39
- "import { tracking } from '@playcraft/ads-tracking';\ntracking.onPlaycraftTrackingInit();\n",
40
- );
41
- fs.writeFileSync(path.join(root, 'src/index.ts'), 'export const unused = 1;\n');
42
- });
43
-
44
- after(() => {
45
- fs.rmSync(root, { recursive: true, force: true });
46
- });
47
-
48
- it('treats @playcraft/adsdk/cjs as an SDK import', () => {
49
- assert.equal(hasSDKImport("import * as adsdk from '@playcraft/adsdk/cjs';"), true);
50
- assert.equal(hasSDKImport("import { sdk } from '@playcraft/adsdk';"), true);
51
- });
52
-
53
- it('detects cocos from builds.config.js and scans assets/scripts only', () => {
54
- assert.equal(detectProjectEngine(root), 'cocos');
55
- const roots = resolveScanRoots(root, 'cocos').map((dir) => path.relative(root, dir));
56
- assert.deepEqual(roots, ['assets/scripts']);
57
- });
58
-
59
- it('passes required tracking checks for a cocos SDK wrapper project', () => {
60
- const result = validateTracking(root, { engine: 'cocos' });
61
- assert.equal(result.stats.engine, 'cocos');
62
- assert.deepEqual(result.stats.scanRoots, ['assets/scripts']);
63
- assert.equal(result.integrationType, 'sdk');
64
- assert.equal(result.success, true, result.errors.join('\n'));
65
- assert.equal(result.stats.hasSDKImport, true);
66
- });
67
-
68
- it('does not let library ads-tracking imports flip the integration type', () => {
69
- const result = validateTracking(root, { engine: 'cocos' });
70
- assert.equal(result.stats.hasTrackingImport, false);
71
- assert.ok(result.stats.scannedFiles < 10);
72
- });
73
-
74
- it('scans src for phaser', () => {
75
- const phaserRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'tracking-phaser-'));
76
- fs.mkdirSync(path.join(phaserRoot, 'src'), { recursive: true });
77
- fs.mkdirSync(path.join(phaserRoot, 'library'), { recursive: true });
78
- fs.writeFileSync(path.join(phaserRoot, 'src/main.ts'), SDK_SOURCE.replace('/cjs', ''));
79
- fs.writeFileSync(
80
- path.join(phaserRoot, 'library/noise.js'),
81
- "import { tracking } from '@playcraft/ads-tracking';\n",
82
- );
83
- try {
84
- const result = validateTracking(phaserRoot, { engine: 'phaser' });
85
- assert.deepEqual(result.stats.scanRoots, ['src']);
86
- assert.equal(result.integrationType, 'sdk');
87
- assert.equal(result.success, true, result.errors.join('\n'));
88
- } finally {
89
- fs.rmSync(phaserRoot, { recursive: true, force: true });
90
- }
91
- });
92
- });
10
+ `;describe("tracking validator engine scan roots",()=>{let root;before(()=>{root=fs.mkdtempSync(path.join(os.tmpdir(),"tracking-scan-"));fs.mkdirSync(path.join(root,"assets/scripts/game"),{recursive:true});fs.mkdirSync(path.join(root,"assets/scenes"),{recursive:true});fs.mkdirSync(path.join(root,"library/import"),{recursive:true});fs.mkdirSync(path.join(root,"src"),{recursive:true});fs.writeFileSync(path.join(root,"builds.config.js"),"module.exports = { engine: 'cocos' };\n");fs.writeFileSync(path.join(root,"assets/scripts/game/GameRoot.ts"),SDK_SOURCE);fs.writeFileSync(path.join(root,"library/import/noise.js"),"import { tracking } from '@playcraft/ads-tracking';\ntracking.onPlaycraftTrackingInit();\n");fs.writeFileSync(path.join(root,"src/index.ts"),"export const unused = 1;\n")});after(()=>{fs.rmSync(root,{recursive:true,force:true})});it("treats @playcraft/adsdk/cjs as an SDK import",()=>{assert.equal(hasSDKImport("import * as adsdk from '@playcraft/adsdk/cjs';"),true);assert.equal(hasSDKImport("import { sdk } from '@playcraft/adsdk';"),true)});it("detects cocos from builds.config.js and scans assets/scripts only",()=>{assert.equal(detectProjectEngine(root),"cocos");const roots=resolveScanRoots(root,"cocos").map(dir=>path.relative(root,dir));assert.deepEqual(roots,["assets/scripts"])});it("passes required tracking checks for a cocos SDK wrapper project",()=>{const result=validateTracking(root,{engine:"cocos"});assert.equal(result.stats.engine,"cocos");assert.deepEqual(result.stats.scanRoots,["assets/scripts"]);assert.equal(result.integrationType,"sdk");assert.equal(result.success,true,result.errors.join("\n"));assert.equal(result.stats.hasSDKImport,true)});it("does not let library ads-tracking imports flip the integration type",()=>{const result=validateTracking(root,{engine:"cocos"});assert.equal(result.stats.hasTrackingImport,false);assert.ok(result.stats.scannedFiles<10)});it("scans src for phaser",()=>{const phaserRoot=fs.mkdtempSync(path.join(os.tmpdir(),"tracking-phaser-"));fs.mkdirSync(path.join(phaserRoot,"src"),{recursive:true});fs.mkdirSync(path.join(phaserRoot,"library"),{recursive:true});fs.writeFileSync(path.join(phaserRoot,"src/main.ts"),SDK_SOURCE.replace("/cjs",""));fs.writeFileSync(path.join(phaserRoot,"library/noise.js"),"import { tracking } from '@playcraft/ads-tracking';\n");try{const result=validateTracking(phaserRoot,{engine:"phaser"});assert.deepEqual(result.stats.scanRoots,["src"]);assert.equal(result.integrationType,"sdk");assert.equal(result.success,true,result.errors.join("\n"))}finally{fs.rmSync(phaserRoot,{recursive:true,force:true})}})});
package/core/vite.dev.js CHANGED
@@ -1 +1 @@
1
- module.exports = require('./engines/web/vite.dev.js');
1
+ "use strict";module.exports=require("./engines/web/vite.dev.js");
@@ -1 +1 @@
1
- module.exports = require('./engines/web/webpack.build.js');
1
+ "use strict";module.exports=require("./engines/web/webpack.build.js");