@playcraft/devkit 1.0.26 → 1.0.27

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 (52) hide show
  1. package/README.md +262 -0
  2. package/cli/bin/playable-scripts.js +44 -1
  3. package/cli/commands/build.js +170 -22
  4. package/cli/commands/builds.js +13 -2
  5. package/cli/commands/dev.js +7 -1
  6. package/cli/commands/pack.js +308 -39
  7. package/cli/commands/vite-dev.js +7 -1
  8. package/core/batch-build.js +1119 -126
  9. package/core/constants.js +16 -2
  10. package/core/cos-uploader.js +286 -23
  11. package/core/index.js +76 -7
  12. package/core/loaders/gltf-loader.js +74 -28
  13. package/core/options.js +310 -15
  14. package/core/plugins/AdikteevInjectorPlugin.js +26 -4
  15. package/core/plugins/BigoAdsInjectorPlugin.js +21 -4
  16. package/core/plugins/DAPIInjectorPlugin.js +25 -2
  17. package/core/plugins/DebuggerInjectionPlugin.js +31 -3
  18. package/core/plugins/ExitAPIInjectorPlugin.js +57 -3
  19. package/core/plugins/FflateCompressionPlugin.js +231 -40
  20. package/core/plugins/FontInjectionWebpackPlugin.js +46 -4
  21. package/core/plugins/LiftoffInjectorPlugin.js +26 -4
  22. package/core/plugins/MRAIDInjectorPlugin.js +24 -2
  23. package/core/plugins/MintegralInjectorPlugin.js +25 -2
  24. package/core/plugins/PangleInjectorPlugin.js +24 -2
  25. package/core/plugins/SnapchatInjectorPlugin.js +26 -4
  26. package/core/plugins/SocialMediaInjectorPlugin.js +119 -7
  27. package/core/plugins/TikTokInjectorPlugin.js +24 -2
  28. package/core/plugins/UnityInjectorPlugin.js +37 -8
  29. package/core/plugins/ZipPlugin.js +138 -19
  30. package/core/plugins/socialMediaVitePlugin.js +108 -2
  31. package/core/utils/buildDefines.js +29 -2
  32. package/core/utils/buildTemplateString.js +40 -5
  33. package/core/utils/date.js +16 -1
  34. package/core/utils/fontRegistry.js +81 -13
  35. package/core/utils/fontResolver.js +335 -37
  36. package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +42 -7
  37. package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +30 -3
  38. package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +43 -7
  39. package/core/utils/injectSDKPlugins.js +68 -13
  40. package/core/utils/logOptions.js +37 -4
  41. package/core/utils/mergeOptions.js +19 -2
  42. package/core/utils/parseArgvOptions.js +111 -5
  43. package/core/utils/resolveChannelFold2Zip.js +15 -3
  44. package/core/utils/validateThemeData.js +227 -26
  45. package/core/validators/index.d.ts +4 -0
  46. package/core/validators/pre-build-checker.js +297 -21
  47. package/core/validators/tracking-validator.js +358 -40
  48. package/core/vite.dev.js +322 -17
  49. package/core/webpack.build.js +489 -56
  50. package/core/webpack.common.js +177 -11
  51. package/core/webpack.dev.js +82 -5
  52. package/package.json +3 -2
@@ -1,4 +1,7 @@
1
- "use strict";const fs=require("fs");const path=require("path");/**
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
2
5
  * InMobi 追踪宏定义
3
6
  * 文档: https://support.inmobi.com/dsp/in/inmobi-dsp-india/creative-specifications-and-guidelines/
4
7
  *
@@ -7,7 +10,8 @@
7
10
  * 2. 必须包含 INMOBI_DSPMACROS 追踪变量
8
11
  * 3. 引用外部 mraid.js(由 InMobi 平台提供)
9
12
  * 4. 支持 MRAID 3.0 标准
10
- */const InMobiPlaceholders=`<script>
13
+ */
14
+ const InMobiPlaceholders = `<script>
11
15
  var INMOBI_DSPMACROS = {
12
16
  "Ad_Load_Start": ["$P_AD_LOAD_START"],
13
17
  "Ad_Viewable": ["$P_AD_READY"],
@@ -23,14 +27,46 @@
23
27
  "Spent_30_Seconds": ["$P_TIMESPENT_30"]
24
28
  };
25
29
  </script>
26
- <script src="mraid.js"></script>`;/**
30
+ <script src="mraid.js"></script>`;
31
+
32
+ /**
27
33
  * 生成 InMobi 平台所需的 HTML 配置
28
34
  *
29
35
  * 策略:
30
36
  * 1. 使用标准的 HtmlWebpackPlugin 配置(不是 templateContent)
31
37
  * 2. JS 会通过 HtmlInlineScriptPlugin 自动内联到 HTML 中
32
38
  * 3. 通过修改 template 文件注入 InMobi 追踪脚本
33
- */exports.generateInMobiHtmlWebpackPluginConfig=function generateInMobiHtmlWebpackPluginConfig(originalHtmlContentPath,buildOptions){originalHtmlContentPath=originalHtmlContentPath||"src/index.html";const placeholder=InMobiPlaceholders.replaceAll("{GOOGLE_PLAY_URL}",buildOptions.googlePlayUrl).replaceAll("{APP_STORE_URL}",buildOptions.appStoreUrl);// 读取原始 HTML 模板
34
- let htmlContent="";try{htmlContent=fs.readFileSync(path.resolve(originalHtmlContentPath),"utf8")}catch(e){console.warn("[InMobi] Could not read HTML template:",e.message)}// 在 </head> 之前注入 InMobi 追踪脚本
35
- htmlContent=htmlContent.replace("</head>",`${placeholder}\n</head>`);return{filename:"index.html",inject:"head",// webpack 会自动注入 JS,然后 HtmlInlineScriptPlugin 内联
36
- minify:false,templateContent:htmlContent,meta:{charset:"UTF-8",viewport:"width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"}}};
39
+ */
40
+ exports.generateInMobiHtmlWebpackPluginConfig = function generateInMobiHtmlWebpackPluginConfig(
41
+ originalHtmlContentPath,
42
+ buildOptions
43
+ ) {
44
+ originalHtmlContentPath = originalHtmlContentPath || 'src/index.html';
45
+
46
+ const placeholder = InMobiPlaceholders
47
+ .replaceAll('{GOOGLE_PLAY_URL}', buildOptions.googlePlayUrl)
48
+ .replaceAll('{APP_STORE_URL}', buildOptions.appStoreUrl);
49
+
50
+ // 读取原始 HTML 模板
51
+ let htmlContent = '';
52
+ try {
53
+ htmlContent = fs.readFileSync(path.resolve(originalHtmlContentPath), 'utf8');
54
+ } catch (e) {
55
+ console.warn('[InMobi] Could not read HTML template:', e.message);
56
+ }
57
+
58
+ // 在 </head> 之前注入 InMobi 追踪脚本
59
+ htmlContent = htmlContent.replace('</head>', `${placeholder}\n</head>`);
60
+
61
+ return {
62
+ filename: 'index.html',
63
+ inject: 'head', // webpack 会自动注入 JS,然后 HtmlInlineScriptPlugin 内联
64
+ minify: false,
65
+ templateContent: htmlContent,
66
+ meta: {
67
+ charset: 'UTF-8',
68
+ viewport: 'width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no'
69
+ }
70
+ };
71
+ };
72
+
@@ -1,7 +1,22 @@
1
- "use strict";/**
1
+ /**
2
2
  * 根据 AD_NETWORK 和 AD_PROTOCOL 注入对应的渠道 SDK 脚本插件
3
3
  * 此函数被 webpack.dev.js 和 webpack.build.js 共用
4
- */const{ExitAPIInjectorPlugin}=require("../plugins/ExitAPIInjectorPlugin.js");const{DAPIInjectorPlugin}=require("../plugins/DAPIInjectorPlugin.js");const{PangleInjectorPlugin}=require("../plugins/PangleInjectorPlugin.js");const{TikTokInjectorPlugin}=require("../plugins/TikTokInjectorPlugin.js");const{MintegralInjectorPlugin}=require("../plugins/MintegralInjectorPlugin.js");const{MRAIDInjectorPlugin}=require("../plugins/MRAIDInjectorPlugin.js");const{BigoAdsInjectorPlugin}=require("../plugins/BigoAdsInjectorPlugin.js");const{LiftoffInjectorPlugin}=require("../plugins/LiftoffInjectorPlugin.js");const{SnapchatInjectorPlugin}=require("../plugins/SnapchatInjectorPlugin.js");const{AdikteevInjectorPlugin}=require("../plugins/AdikteevInjectorPlugin.js");const{UnityInjectorPlugin}=require("../plugins/UnityInjectorPlugin.js");const{SocialMediaInjectorPlugin}=require("../plugins/SocialMediaInjectorPlugin.js");/**
4
+ */
5
+
6
+ const { ExitAPIInjectorPlugin } = require('../plugins/ExitAPIInjectorPlugin.js');
7
+ const { DAPIInjectorPlugin } = require('../plugins/DAPIInjectorPlugin.js');
8
+ const { PangleInjectorPlugin } = require('../plugins/PangleInjectorPlugin.js');
9
+ const { TikTokInjectorPlugin } = require('../plugins/TikTokInjectorPlugin.js');
10
+ const { MintegralInjectorPlugin } = require('../plugins/MintegralInjectorPlugin.js');
11
+ const { MRAIDInjectorPlugin } = require('../plugins/MRAIDInjectorPlugin.js');
12
+ const { BigoAdsInjectorPlugin } = require('../plugins/BigoAdsInjectorPlugin.js');
13
+ const { LiftoffInjectorPlugin } = require('../plugins/LiftoffInjectorPlugin.js');
14
+ const { SnapchatInjectorPlugin } = require('../plugins/SnapchatInjectorPlugin.js');
15
+ const { AdikteevInjectorPlugin } = require('../plugins/AdikteevInjectorPlugin.js');
16
+ const { UnityInjectorPlugin } = require('../plugins/UnityInjectorPlugin.js');
17
+ const { SocialMediaInjectorPlugin } = require('../plugins/SocialMediaInjectorPlugin.js');
18
+
19
+ /**
5
20
  * 注入渠道 SDK 插件到 webpack 配置中
6
21
  * @param {import('webpack').Configuration} webpackConfig - webpack 配置对象
7
22
  * @param {Object} options - 配置选项
@@ -12,14 +27,54 @@
12
27
  * @param {string} [options.themeName] - 当前主题名
13
28
  * @param {object} [options.themeConfig] - builds.config.js 中的 themes 配置
14
29
  * @param {object} [options.mergedData] - 预合并的主题数据(可选)
15
- */function injectSDKPlugins(webpackConfig,options){const{network:adNetwork,protocol:adProtocol,orientation,projectRoot,themeName,themeConfig,mergedData}=options;// 协议层注入
16
- if("dapi"===adProtocol){webpackConfig.plugins.push(new DAPIInjectorPlugin)}else if("mraid"===adProtocol){// 只有 ironsource 才注入 MRAIDInjectorPlugin
17
- // Unity 使用专门的 UnityInjectorPlugin(在渠道特定注入中处理)
18
- if(adNetwork==="ironsource"){webpackConfig.plugins.push(new MRAIDInjectorPlugin)}}// 渠道特定注入
19
- if(adNetwork==="google"){webpackConfig.plugins.push(new ExitAPIInjectorPlugin(orientation))}else if(adNetwork==="unity"){// Unity Ads 使用专门的 UnityInjectorPlugin
20
- webpackConfig.plugins.push(new UnityInjectorPlugin)}else if(adNetwork==="pangle"){webpackConfig.plugins.push(new PangleInjectorPlugin)}else if(adNetwork==="tiktok"){webpackConfig.plugins.push(new TikTokInjectorPlugin)}else if(adNetwork==="mintegral"){webpackConfig.plugins.push(new MintegralInjectorPlugin)}else if(adNetwork==="bigoads"){// BigoAds 在 dev 模式下注入模拟配置
21
- webpackConfig.plugins.push(new BigoAdsInjectorPlugin)}else if(adNetwork==="liftoff"){webpackConfig.plugins.push(new LiftoffInjectorPlugin)}else if(adNetwork==="snapchat"){// Snapchat 注入 ScPlayableAd SDK
22
- webpackConfig.plugins.push(new SnapchatInjectorPlugin)}else if(adNetwork==="adikteev"){// Adikteev 注入 MRAID mock 和占位符变量
23
- webpackConfig.plugins.push(new AdikteevInjectorPlugin)}else if(adNetwork==="social_media"){// social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn 爬取时
24
- // 能拿到正确的标题/描述/预览图。注意 Telegram / Slack / Discord 也读 OG meta
25
- webpackConfig.plugins.push(new SocialMediaInjectorPlugin({projectRoot,themeName,themeConfig,mergedData}))}}exports.injectSDKPlugins=injectSDKPlugins;
30
+ */
31
+ function injectSDKPlugins(webpackConfig, options) {
32
+ const { network: adNetwork, protocol: adProtocol, orientation, projectRoot, themeName, themeConfig, mergedData } = options;
33
+
34
+ // 协议层注入
35
+ if ('dapi' === adProtocol) {
36
+ webpackConfig.plugins.push(new DAPIInjectorPlugin());
37
+ } else if ('mraid' === adProtocol) {
38
+ // 只有 ironsource 才注入 MRAIDInjectorPlugin
39
+ // Unity 使用专门的 UnityInjectorPlugin(在渠道特定注入中处理)
40
+ if (adNetwork === 'ironsource') {
41
+ webpackConfig.plugins.push(new MRAIDInjectorPlugin());
42
+ }
43
+ }
44
+
45
+ // 渠道特定注入
46
+ if (adNetwork === 'google') {
47
+ webpackConfig.plugins.push(new ExitAPIInjectorPlugin(orientation));
48
+ } else if (adNetwork === 'unity') {
49
+ // Unity Ads 使用专门的 UnityInjectorPlugin
50
+ webpackConfig.plugins.push(new UnityInjectorPlugin());
51
+ } else if (adNetwork === 'pangle') {
52
+ webpackConfig.plugins.push(new PangleInjectorPlugin());
53
+ } else if (adNetwork === 'tiktok') {
54
+ webpackConfig.plugins.push(new TikTokInjectorPlugin());
55
+ } else if (adNetwork === 'mintegral') {
56
+ webpackConfig.plugins.push(new MintegralInjectorPlugin());
57
+ } else if (adNetwork === 'bigoads') {
58
+ // BigoAds 在 dev 模式下注入模拟配置
59
+ webpackConfig.plugins.push(new BigoAdsInjectorPlugin());
60
+ } else if (adNetwork === 'liftoff') {
61
+ webpackConfig.plugins.push(new LiftoffInjectorPlugin());
62
+ } else if (adNetwork === 'snapchat') {
63
+ // Snapchat 注入 ScPlayableAd SDK
64
+ webpackConfig.plugins.push(new SnapchatInjectorPlugin());
65
+ } else if (adNetwork === 'adikteev') {
66
+ // Adikteev 注入 MRAID mock 和占位符变量
67
+ webpackConfig.plugins.push(new AdikteevInjectorPlugin());
68
+ } else if (adNetwork === 'social_media') {
69
+ // social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn 爬取时
70
+ // 能拿到正确的标题/描述/预览图。注意 Telegram / Slack / Discord 也读 OG meta
71
+ webpackConfig.plugins.push(new SocialMediaInjectorPlugin({
72
+ projectRoot,
73
+ themeName,
74
+ themeConfig,
75
+ mergedData,
76
+ }));
77
+ }
78
+ }
79
+
80
+ exports.injectSDKPlugins = injectSDKPlugins;
@@ -1,5 +1,38 @@
1
- "use strict";var prettyjson=require("prettyjson");/**
1
+ var prettyjson = require('prettyjson');
2
+
3
+ /**
2
4
  * Log provided options into console output
3
- */exports.logOptions=function logOptions(options){let logOptions={mode:process.env.NODE_ENV,...options};let isProduction=false;if(process.env.NODE_ENV==="production"){isProduction=true;delete logOptions.port;delete logOptions.open}else if(process.env.NODE_ENV==="development"){delete logOptions.outDir}if(Object.keys(logOptions.compilation).length===0||!isProduction)delete logOptions.compilation;if(Object.keys(logOptions.adNetworkNames).length===0||!isProduction)delete logOptions.adNetworkNames;if(Object.keys(logOptions.defines).length===0)delete logOptions.defines;if(logOptions.zip===false||!isProduction)delete logOptions.zip;if(logOptions.tsConfig==="tsconfig.json")delete logOptions.tsConfig;if(logOptions.jsConfig==="jsconfig.json")delete logOptions.jsConfig;if(logOptions.buildConfig==="build.json")delete logOptions.buildConfig;if(logOptions.language==="en")delete logOptions.language;if(logOptions.orientation==="both")delete logOptions.orientation;// 在 dev 模式下,如果 network 为默认值 preview 则不显示
4
- if(!isProduction&&logOptions.network==="preview")delete logOptions.network;// 在 dev 模式下,如果 protocol 为默认值 none 则不显示
5
- if(!isProduction&&logOptions.protocol==="none")delete logOptions.protocol;delete logOptions.filename;delete logOptions.app;delete logOptions.name;delete logOptions.googlePlayUrl;delete logOptions.appStoreUrl;if(logOptions.obfuscateLevel===2)delete logOptions.obfuscateLevel;console.log(prettyjson.render(logOptions,{},2))};
5
+ */
6
+ exports.logOptions = function logOptions(options) {
7
+ let logOptions = { mode: process.env.NODE_ENV, ...options };
8
+ let isProduction = false;
9
+ if (process.env.NODE_ENV === 'production') {
10
+ isProduction = true;
11
+ delete logOptions.port;
12
+ delete logOptions.open;
13
+ } else if (process.env.NODE_ENV === 'development') {
14
+ delete logOptions.outDir;
15
+ }
16
+
17
+ if (Object.keys(logOptions.compilation).length === 0 || !isProduction) delete logOptions.compilation;
18
+ if (Object.keys(logOptions.adNetworkNames).length === 0 || !isProduction) delete logOptions.adNetworkNames;
19
+ if (Object.keys(logOptions.defines).length === 0) delete logOptions.defines;
20
+ if (logOptions.zip === false || !isProduction) delete logOptions.zip;
21
+ if (logOptions.tsConfig === 'tsconfig.json') delete logOptions.tsConfig;
22
+ if (logOptions.jsConfig === 'jsconfig.json') delete logOptions.jsConfig;
23
+ if (logOptions.buildConfig === 'build.json') delete logOptions.buildConfig;
24
+ if (logOptions.language === 'en') delete logOptions.language;
25
+ if (logOptions.orientation === 'both') delete logOptions.orientation;
26
+ // 在 dev 模式下,如果 network 为默认值 preview 则不显示
27
+ if (!isProduction && logOptions.network === 'preview') delete logOptions.network;
28
+ // 在 dev 模式下,如果 protocol 为默认值 none 则不显示
29
+ if (!isProduction && logOptions.protocol === 'none') delete logOptions.protocol;
30
+ delete logOptions.filename;
31
+ delete logOptions.app;
32
+ delete logOptions.name;
33
+ delete logOptions.googlePlayUrl;
34
+ delete logOptions.appStoreUrl;
35
+ if (logOptions.obfuscateLevel === 2) delete logOptions.obfuscateLevel;
36
+
37
+ console.log(prettyjson.render(logOptions, {}, 2));
38
+ };
@@ -1,6 +1,23 @@
1
- "use strict";/**
1
+ /**
2
2
  * Merges two option objects with deep merge for 'defines' and 'build' properties
3
3
  * @param {import('../index').CLIOptions} options1 - First options object
4
4
  * @param {Partial<import('../index').CLIOptions>} [options2] - Second options object
5
5
  * @returns {import('../index').CLIOptions} Merged options object with combined defines and build properties
6
- */exports.mergeOptions=function mergeOptions(options1,options2){if(!options1)return{};if(!options2)return options1;const defines=Object.assign({},options1.defines,options2.defines);const build=Object.assign({},options1.build,options2.build);const compilation=Object.assign({},options1.compilation,options2.compilation);const adNetworkNames=Object.assign({},options1.adNetworkNames,options2.adNetworkNames);const options=Object.assign({},options1,options2);options.defines=defines;options.compilation=compilation;options.adNetworkNames=adNetworkNames;options.build=build;return options};
6
+ */
7
+ exports.mergeOptions = function mergeOptions(options1, options2) {
8
+ if (!options1) return {};
9
+ if (!options2) return options1;
10
+
11
+ const defines = Object.assign({}, options1.defines, options2.defines);
12
+ const build = Object.assign({}, options1.build, options2.build);
13
+ const compilation = Object.assign({}, options1.compilation, options2.compilation);
14
+ const adNetworkNames = Object.assign({}, options1.adNetworkNames, options2.adNetworkNames);
15
+ const options = Object.assign({}, options1, options2);
16
+
17
+ options.defines = defines;
18
+ options.compilation = compilation;
19
+ options.adNetworkNames = adNetworkNames;
20
+ options.build = build;
21
+
22
+ return options;
23
+ };
@@ -1,8 +1,114 @@
1
- "use strict";/** @type {string[]} List of supported advertising networks */const allowedAdNetworks=["preview","applovin","unity","google","ironsource","facebook","moloco","adcolony","mintegral","vungle","tapjoy","snapchat","tiktok","appreciate","chartboost","pangle","mytarget","liftoff","smadex","adikteev","bigabid","inmobi","bigoads","social_media"];/** @type {AD_PROTOCOL[]} List of supported advertising protocols */const allowedAdProtocols=["none","mraid","dapi"];/** @type {AD_NETWORK[]} List of advertising partners that support MRAID protocol */const mraidPartners=["ironsource","applovin","unity","appreciate","chartboost","mytarget","liftoff","adcolony","adikteev","bigabid","inmobi"];/** @type {LANGUAGE[]} */const allowedLanguages=["auto","en","es","zh","hi","ar","fr","de","ja","pt"];/** @type {ORIENTATION[]} */const allowedOrientations=["both","portrait","landscape","square"];/**
1
+ /** @type {string[]} List of supported advertising networks */
2
+ const allowedAdNetworks = [
3
+ 'preview',
4
+ 'applovin',
5
+ 'unity',
6
+ 'google',
7
+ 'ironsource',
8
+ 'facebook',
9
+ 'moloco',
10
+ 'adcolony',
11
+ 'mintegral',
12
+ 'vungle',
13
+ 'tapjoy',
14
+ 'snapchat',
15
+ 'tiktok',
16
+ 'appreciate',
17
+ 'chartboost',
18
+ 'pangle',
19
+ 'mytarget',
20
+ 'liftoff',
21
+ 'smadex',
22
+ 'adikteev',
23
+ 'bigabid',
24
+ 'inmobi',
25
+ 'bigoads',
26
+ 'social_media'
27
+ ];
28
+ /** @type {AD_PROTOCOL[]} List of supported advertising protocols */
29
+ const allowedAdProtocols = ['none', 'mraid', 'dapi'];
30
+
31
+ /** @type {AD_NETWORK[]} List of advertising partners that support MRAID protocol */
32
+ const mraidPartners = [
33
+ 'ironsource',
34
+ 'applovin',
35
+ 'unity',
36
+ 'appreciate',
37
+ 'chartboost',
38
+ 'mytarget',
39
+ 'liftoff',
40
+ 'adcolony',
41
+ 'adikteev',
42
+ 'bigabid',
43
+ 'inmobi'
44
+ ];
45
+
46
+ /** @type {LANGUAGE[]} */
47
+ const allowedLanguages = ['auto', 'en', 'es', 'zh', 'hi', 'ar', 'fr', 'de', 'ja', 'pt'];
48
+
49
+ /** @type {ORIENTATION[]} */
50
+ const allowedOrientations = ['both', 'portrait', 'landscape', 'square'];
51
+
52
+ /**
2
53
  * Parses command line arguments based on provided options configuration
3
54
  * @param {import('../index').CLIOptionConfig[]} posiibleOptions - Array of possible options to parse
4
55
  * @returns {Record<string, any>} Parsed options object with values from command line arguments
5
- */exports.parseArgvOptions=function parseArgvOptions(posiibleOptions){const argvOptions={};// Track which options were explicitly set via CLI args
6
- const cliExplicitKeys=new Set;for(let possibleOption of posiibleOptions){if(possibleOption.defaultValue!==undefined)argvOptions[possibleOption.alias||possibleOption.name]=possibleOption.defaultValue}let adNetwork=null;for(let i=2;i<process.argv.length;i++){let key=process.argv[i];let inlineValue=null;// 支持 --key=value 格式
7
- if(key.includes("=")){const eqIndex=key.indexOf("=");inlineValue=key.slice(eqIndex+1);key=key.slice(0,eqIndex)}const allowedOption=posiibleOptions.find(e=>"--"+e.name===key);if(allowedOption){let value=true;if(allowedOption.hasValue){// 优先使用内联值(--key=value),否则使用下一个参数
8
- value=inlineValue!==null?inlineValue:process.argv[++i];if(allowedOption.parser)value=allowedOption.parser(value)}const optionKey=allowedOption.alias||allowedOption.name;argvOptions[optionKey]=value;cliExplicitKeys.add(optionKey)}else if(!adNetwork)adNetwork=key}if(posiibleOptions.find(e=>e.name==="network")){if(adNetwork&&allowedAdNetworks.includes(adNetwork)){argvOptions["network"]=adNetwork}if(posiibleOptions.find(e=>e.name==="protocol")){if(mraidPartners.includes(argvOptions["network"])&&argvOptions["protocol"]==="none"){argvOptions["protocol"]="mraid"}}}argvOptions._cliExplicitKeys=cliExplicitKeys;return argvOptions};exports.allowedAdNetworks=allowedAdNetworks;exports.allowedAdProtocols=allowedAdProtocols;exports.mraidPartners=mraidPartners;exports.allowedLanguages=allowedLanguages;exports.allowedOrientations=allowedOrientations;
56
+ */
57
+ exports.parseArgvOptions = function parseArgvOptions(posiibleOptions) {
58
+ const argvOptions = {};
59
+ // Track which options were explicitly set via CLI args
60
+ const cliExplicitKeys = new Set();
61
+
62
+ for (let possibleOption of posiibleOptions) {
63
+ if (possibleOption.defaultValue !== undefined)
64
+ argvOptions[possibleOption.alias || possibleOption.name] = possibleOption.defaultValue;
65
+ }
66
+
67
+ let adNetwork = null;
68
+
69
+ for (let i = 2; i < process.argv.length; i++) {
70
+ let key = process.argv[i];
71
+ let inlineValue = null;
72
+
73
+ // 支持 --key=value 格式
74
+ if (key.includes('=')) {
75
+ const eqIndex = key.indexOf('=');
76
+ inlineValue = key.slice(eqIndex + 1);
77
+ key = key.slice(0, eqIndex);
78
+ }
79
+
80
+ const allowedOption = posiibleOptions.find((e) => '--' + e.name === key);
81
+
82
+ if (allowedOption) {
83
+ let value = true;
84
+ if (allowedOption.hasValue) {
85
+ // 优先使用内联值(--key=value),否则使用下一个参数
86
+ value = inlineValue !== null ? inlineValue : process.argv[++i];
87
+ if (allowedOption.parser) value = allowedOption.parser(value);
88
+ }
89
+ const optionKey = allowedOption.alias || allowedOption.name;
90
+ argvOptions[optionKey] = value;
91
+ cliExplicitKeys.add(optionKey);
92
+ } else if (!adNetwork) adNetwork = key;
93
+ }
94
+
95
+ if (posiibleOptions.find((e) => e.name === 'network')) {
96
+ if (adNetwork && allowedAdNetworks.includes(adNetwork)) {
97
+ argvOptions['network'] = adNetwork;
98
+ }
99
+ if (posiibleOptions.find((e) => e.name === 'protocol')) {
100
+ if (mraidPartners.includes(argvOptions['network']) && argvOptions['protocol'] === 'none') {
101
+ argvOptions['protocol'] = 'mraid';
102
+ }
103
+ }
104
+ }
105
+
106
+ argvOptions._cliExplicitKeys = cliExplicitKeys;
107
+ return argvOptions;
108
+ };
109
+
110
+ exports.allowedAdNetworks = allowedAdNetworks;
111
+ exports.allowedAdProtocols = allowedAdProtocols;
112
+ exports.mraidPartners = mraidPartners;
113
+ exports.allowedLanguages = allowedLanguages;
114
+ exports.allowedOrientations = allowedOrientations;
@@ -1,4 +1,4 @@
1
- "use strict";/**
1
+ /**
2
2
  * 解析 isChannelFold2Zip 相关标志
3
3
  *
4
4
  * isChannelFold2Zip:所有渠道(排除 preview)输出 dist/渠道名称.zip
@@ -10,5 +10,17 @@
10
10
  * @param {string} params.adNetwork - 当前渠道名称
11
11
  * @param {boolean} params.isZipOutput - 当前渠道是否本身就走 ZIP 输出流程
12
12
  * @returns {{ isChannelFold2Zip: boolean, isZipOutputFinal: boolean }}
13
- */function resolveChannelFold2Zip({isChannelFold2ZipOption,adNetwork,isZipOutput}){const isChannelFold2Zip=!!(isChannelFold2ZipOption&&adNetwork!=="preview");// 非 ZIP 渠道启用 isChannelFold2Zip 时,需要强制走 ZIP 输出流程
14
- const isZipOutputFinal=isZipOutput||isChannelFold2Zip;if(isChannelFold2Zip){console.log(`✅ isChannelFold2Zip enabled: output will be dist/${adNetwork}.zip`)}return{isChannelFold2Zip,isZipOutputFinal}}exports.resolveChannelFold2Zip=resolveChannelFold2Zip;
13
+ */
14
+ function resolveChannelFold2Zip({ isChannelFold2ZipOption, adNetwork, isZipOutput }) {
15
+ const isChannelFold2Zip = !!(isChannelFold2ZipOption && adNetwork !== 'preview');
16
+ // 非 ZIP 渠道启用 isChannelFold2Zip 时,需要强制走 ZIP 输出流程
17
+ const isZipOutputFinal = isZipOutput || isChannelFold2Zip;
18
+
19
+ if (isChannelFold2Zip) {
20
+ console.log(`✅ isChannelFold2Zip enabled: output will be dist/${adNetwork}.zip`);
21
+ }
22
+
23
+ return { isChannelFold2Zip, isZipOutputFinal };
24
+ }
25
+
26
+ exports.resolveChannelFold2Zip = resolveChannelFold2Zip;