codeplay-common 4.8.2 → 4.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/files/take-screen-image.js +76 -25
- package/package.json +1 -1
- package/scripts/sync-files.js +2 -0
- package/scripts/uninstall.js +15 -1
- package/files/scripts-screenshot/screenshot/screenshot-copy.json +0 -3
- package/files/scripts-screenshot/screenshot/screenshot-info.json +0 -1737
- /package/files/{scripts-screenshot → scripts}/screenshot/background-decorations.js +0 -0
- /package/files/{scripts-screenshot → scripts}/screenshot/frame-samples.js +0 -0
package/README.md
CHANGED
|
@@ -33,6 +33,21 @@ If `onesignal-cordova-plugin` is declared or installed, the pre-build script war
|
|
|
33
33
|
runs `npm uninstall onesignal-cordova-plugin`. It stops if removal fails or active
|
|
34
34
|
package imports remain. Legacy OneSignal patching and helper downloads are disabled.
|
|
35
35
|
|
|
36
|
+
## Screenshot data
|
|
37
|
+
|
|
38
|
+
Shared screenshot helpers are installed into `scripts/screenshot/` and updated with
|
|
39
|
+
the package. App-specific data is not bundled with the package.
|
|
40
|
+
During an upgrade, cleanup removes only the two legacy helpers `frame-samples.js`
|
|
41
|
+
and `background-decorations.js` from `scripts-screenshot/screenshot/`, preserving
|
|
42
|
+
the folder, JSON data, and other app files.
|
|
43
|
+
|
|
44
|
+
`take-screen-image.js` creates `scripts-screenshot/screenshot/` and empty
|
|
45
|
+
`screenshot-copy.json` and `screenshot-info.json` files when needed. Existing files
|
|
46
|
+
are preserved during initialization, package installation, and cleanup. Capture
|
|
47
|
+
updates screenshot information; the AI text-generation workflow fills screenshot
|
|
48
|
+
copy. `--delete` removes matching records, and screenshot runs reconcile records
|
|
49
|
+
against the captured images (except dry runs and `--refresh-info`).
|
|
50
|
+
|
|
36
51
|
## Agent instructions
|
|
37
52
|
|
|
38
53
|
Agent instructions are updated during `npm run build`, not during npm installation.
|
|
@@ -26,12 +26,12 @@ const path = require('node:path');
|
|
|
26
26
|
const readline = require('node:readline/promises');
|
|
27
27
|
const { spawn, spawnSync } = require('node:child_process');
|
|
28
28
|
const sharp = require('sharp');
|
|
29
|
-
const { frameStyles, createFrameSamples } = require('./scripts
|
|
29
|
+
const { frameStyles, createFrameSamples } = require('./scripts/screenshot/frame-samples.js');
|
|
30
30
|
const {
|
|
31
31
|
getDecorationSeed,
|
|
32
32
|
createPromotionalDecorations,
|
|
33
33
|
getPromotionalDecorationStyles,
|
|
34
|
-
} = require('./scripts
|
|
34
|
+
} = require('./scripts/screenshot/background-decorations.js');
|
|
35
35
|
|
|
36
36
|
const screenshotDirectory = path.join(__dirname, 'Auto-Screenshot', 'Store-image-Screenshot');
|
|
37
37
|
const inFrameDirectory = path.join(__dirname, 'Auto-Screenshot', 'Store-image-Frame');
|
|
@@ -727,6 +727,20 @@ function deleteMatchingImages(input) {
|
|
|
727
727
|
for (const filePath of deletedFiles) console.log(`Deleted: ${filePath}`);
|
|
728
728
|
}
|
|
729
729
|
|
|
730
|
+
function initializeScreenshotData() {
|
|
731
|
+
for (const [filePath, version] of [
|
|
732
|
+
[screenshotCopyPath, 1],
|
|
733
|
+
[screenshotInfoPath, 2],
|
|
734
|
+
]) {
|
|
735
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
736
|
+
try {
|
|
737
|
+
fs.writeFileSync(filePath, `${JSON.stringify({ version, screenshots: {} }, null, 2)}\n`, { flag: 'wx' });
|
|
738
|
+
} catch (error) {
|
|
739
|
+
if (error.code !== 'EEXIST') throw error;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
730
744
|
function readScreenshotRecordSource(filePath) {
|
|
731
745
|
if (!fs.existsSync(filePath)) return { screenshots: {} };
|
|
732
746
|
|
|
@@ -913,21 +927,21 @@ async function getWebViewTarget(localPort) {
|
|
|
913
927
|
&& target.url !== 'about:blank'
|
|
914
928
|
));
|
|
915
929
|
|
|
916
|
-
const
|
|
930
|
+
for (const target of pageTargets) {
|
|
931
|
+
const client = new CdpClient(target.webSocketDebuggerUrl);
|
|
917
932
|
try {
|
|
918
|
-
|
|
933
|
+
await client.connect();
|
|
934
|
+
const details = await getPageDetails(client);
|
|
935
|
+
if (details.width > 0 && details.height > 0 && details.hasAppPage) {
|
|
936
|
+
return target;
|
|
937
|
+
}
|
|
919
938
|
} catch {
|
|
920
|
-
|
|
939
|
+
// A target may close while discovering the active app WebView.
|
|
940
|
+
} finally {
|
|
941
|
+
client.close();
|
|
921
942
|
}
|
|
922
|
-
});
|
|
923
|
-
|
|
924
|
-
const target = visibleTarget || pageTargets[0];
|
|
925
|
-
|
|
926
|
-
if (!target) {
|
|
927
|
-
throw new Error('No rendered page was found in the app WebView.');
|
|
928
943
|
}
|
|
929
|
-
|
|
930
|
-
return target;
|
|
944
|
+
throw new Error('No visible Framework7 app page was found. Open the app page and retry; ad WebViews cannot be captured.');
|
|
931
945
|
}
|
|
932
946
|
|
|
933
947
|
async function getPageDetails(client) {
|
|
@@ -938,6 +952,14 @@ async function getPageDetails(client) {
|
|
|
938
952
|
width: innerWidth,
|
|
939
953
|
height: innerHeight,
|
|
940
954
|
devicePixelRatio: devicePixelRatio,
|
|
955
|
+
hasAppPage: [...document.querySelectorAll('.view .page')].some((page) => {
|
|
956
|
+
const bounds = page.getBoundingClientRect();
|
|
957
|
+
const style = getComputedStyle(page);
|
|
958
|
+
return style.display !== 'none' && style.visibility !== 'hidden'
|
|
959
|
+
&& bounds.width > 0 && bounds.height > 0
|
|
960
|
+
&& bounds.bottom > 0 && bounds.right > 0
|
|
961
|
+
&& bounds.top < innerHeight && bounds.left < innerWidth;
|
|
962
|
+
}),
|
|
941
963
|
readyState: document.readyState
|
|
942
964
|
})`,
|
|
943
965
|
returnByValue: true,
|
|
@@ -1027,7 +1049,7 @@ async function capturePageSnapshot(client) {
|
|
|
1027
1049
|
? element.closest('label, .item-content, .input')
|
|
1028
1050
|
: element;
|
|
1029
1051
|
const preferredLabel = labelRoot?.querySelector(
|
|
1030
|
-
'.item-title, .button-label, strong, .dialog-button-text',
|
|
1052
|
+
'.item-title, .button-label, strong, .dialog-button-text, .homeboxtitle',
|
|
1031
1053
|
);
|
|
1032
1054
|
const textRoot = preferredLabel || labelRoot || element;
|
|
1033
1055
|
const clone = textRoot.cloneNode(true);
|
|
@@ -1051,7 +1073,7 @@ async function capturePageSnapshot(client) {
|
|
|
1051
1073
|
if (!root) return [];
|
|
1052
1074
|
const records = [];
|
|
1053
1075
|
const seen = new Set();
|
|
1054
|
-
const selector = 'button,
|
|
1076
|
+
const selector = 'button, .button, [role="button"], .list-button, .dialog-button';
|
|
1055
1077
|
for (const element of root.querySelectorAll(selector)) {
|
|
1056
1078
|
if (!isVisible(element)) continue;
|
|
1057
1079
|
const label = getElementLabel(element);
|
|
@@ -1123,6 +1145,9 @@ async function capturePageSnapshot(client) {
|
|
|
1123
1145
|
const activePage = visiblePages.find((page) => page.classList.contains('page-current'))
|
|
1124
1146
|
|| visiblePages[visiblePages.length - 1]
|
|
1125
1147
|
|| null;
|
|
1148
|
+
if (!activePage) {
|
|
1149
|
+
throw new Error('No visible app page was found; screenshot information was not captured.');
|
|
1150
|
+
}
|
|
1126
1151
|
const overlaySelector = [
|
|
1127
1152
|
'.dialog.modal-in',
|
|
1128
1153
|
'.popup.modal-in',
|
|
@@ -1147,12 +1172,12 @@ async function capturePageSnapshot(client) {
|
|
|
1147
1172
|
].join(',');
|
|
1148
1173
|
const pageHeadings = collectUiText(
|
|
1149
1174
|
activePage,
|
|
1150
|
-
'h1, h2, h3, .navbar .title, .t-section-heading, .headTitle',
|
|
1175
|
+
'h1, h2, h3, .navbar .title, .t-section-heading, .headTitle, .home-hero-title, .home-section-title',
|
|
1151
1176
|
10,
|
|
1152
1177
|
);
|
|
1153
1178
|
const pageControls = collectUiText(
|
|
1154
1179
|
activePage,
|
|
1155
|
-
'button, [role="button"], label, .item-title, .item-subtitle, .list-button, option:checked',
|
|
1180
|
+
'button, [role="button"], label, .item-title, .item-subtitle, .list-button, option:checked, .homeboxtitle',
|
|
1156
1181
|
30,
|
|
1157
1182
|
);
|
|
1158
1183
|
const overlayText = collectUiText(activeOverlay, textSelector, 35);
|
|
@@ -1170,6 +1195,8 @@ async function capturePageSnapshot(client) {
|
|
|
1170
1195
|
params: Object.keys(f7Route.params || {}),
|
|
1171
1196
|
query: Object.keys(f7Route.query || {}),
|
|
1172
1197
|
} : null;
|
|
1198
|
+
const themeAttribute = document.documentElement.getAttribute('data-theme')
|
|
1199
|
+
|| document.body.getAttribute('data-theme');
|
|
1173
1200
|
const screenInfo = {
|
|
1174
1201
|
documentTitle: normalizeUiText(document.title),
|
|
1175
1202
|
route: {
|
|
@@ -1181,16 +1208,16 @@ async function capturePageSnapshot(client) {
|
|
|
1181
1208
|
dataName: activePage.getAttribute('data-name') || '',
|
|
1182
1209
|
id: activePage.id || '',
|
|
1183
1210
|
classes: getStableClasses(activePage),
|
|
1184
|
-
navbarTitle: collectUiText(activePage, '.navbar .title', 1)[0] || '',
|
|
1211
|
+
navbarTitle: collectUiText(activePage, '.navbar .title, .navbar .home-brand-text', 1)[0] || '',
|
|
1185
1212
|
headings: pageHeadings,
|
|
1186
1213
|
sections: collectUiText(
|
|
1187
1214
|
activePage,
|
|
1188
|
-
'h1, h2, h3, legend, .t-section-heading, .t-output-choice-heading, .headTitle',
|
|
1215
|
+
'h1, h2, h3, legend, .t-section-heading, .t-output-choice-heading, .headTitle, .home-hero-title, .home-section-title',
|
|
1189
1216
|
20,
|
|
1190
1217
|
),
|
|
1191
1218
|
descriptions: collectUiText(
|
|
1192
1219
|
activePage,
|
|
1193
|
-
'p, small, .item-subtitle, .item-after, .t-settings-footnote',
|
|
1220
|
+
'p, small, .item-subtitle, .item-after, .t-settings-footnote, .home-hero-kicker, .home-hero-subtitle, .home-stat, .homebox-meta',
|
|
1194
1221
|
30,
|
|
1195
1222
|
),
|
|
1196
1223
|
controls: pageControls,
|
|
@@ -1218,10 +1245,12 @@ async function capturePageSnapshot(client) {
|
|
|
1218
1245
|
)),
|
|
1219
1246
|
inputs: overlayInputs,
|
|
1220
1247
|
} : null,
|
|
1221
|
-
theme:
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1248
|
+
theme: themeAttribute === 'dark' || themeAttribute === 'light'
|
|
1249
|
+
? themeAttribute
|
|
1250
|
+
: document.documentElement.classList.contains('theme-dark')
|
|
1251
|
+
|| document.body.classList.contains('theme-dark')
|
|
1252
|
+
? 'dark'
|
|
1253
|
+
: 'light',
|
|
1225
1254
|
viewport: {
|
|
1226
1255
|
width: innerWidth,
|
|
1227
1256
|
height: innerHeight,
|
|
@@ -3351,7 +3380,25 @@ async function captureFramedScreenshot(
|
|
|
3351
3380
|
await client.send('Runtime.evaluate', {
|
|
3352
3381
|
expression: `new Promise((resolve) => {
|
|
3353
3382
|
const image = document.querySelector('img');
|
|
3354
|
-
const ready = () => requestAnimationFrame(() =>
|
|
3383
|
+
const ready = () => requestAnimationFrame(() => {
|
|
3384
|
+
const copy = document.querySelector('.promo-copy');
|
|
3385
|
+
const device = document.querySelector('.device');
|
|
3386
|
+
if (copy && device && window.innerHeight > window.innerWidth) {
|
|
3387
|
+
const gap = Math.max(16, Math.min(40, window.innerHeight * 0.02));
|
|
3388
|
+
const deviceTop = copy.getBoundingClientRect().bottom + gap;
|
|
3389
|
+
const deviceBounds = device.getBoundingClientRect();
|
|
3390
|
+
const availableHeight = window.innerHeight * 0.97 - deviceTop;
|
|
3391
|
+
const availableWidth = window.innerWidth * 0.9;
|
|
3392
|
+
const scale = Math.min(1, availableHeight / deviceBounds.height, availableWidth / deviceBounds.width);
|
|
3393
|
+
if (scale > 0) {
|
|
3394
|
+
device.style.top = deviceTop + 'px';
|
|
3395
|
+
device.style.bottom = 'auto';
|
|
3396
|
+
device.style.transformOrigin = 'top center';
|
|
3397
|
+
device.style.transform = 'translateX(-50%) scale(' + scale + ')';
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
requestAnimationFrame(resolve);
|
|
3401
|
+
});
|
|
3355
3402
|
if (image.complete) ready();
|
|
3356
3403
|
else {
|
|
3357
3404
|
image.addEventListener('load', ready, { once: true });
|
|
@@ -3793,6 +3840,10 @@ async function main() {
|
|
|
3793
3840
|
|
|
3794
3841
|
options = await getInteractiveOptions(options);
|
|
3795
3842
|
|
|
3843
|
+
if (!options.dryRun) {
|
|
3844
|
+
initializeScreenshotData();
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3796
3847
|
if (!options.dryRun && !options.refreshInfo) {
|
|
3797
3848
|
reconcileScreenshotRecords();
|
|
3798
3849
|
}
|
package/package.json
CHANGED
package/scripts/sync-files.js
CHANGED
|
@@ -25,6 +25,8 @@ function copyFolderSync(source, destination) {
|
|
|
25
25
|
|
|
26
26
|
// Copy all files from `common-build-files/files/` to the project root
|
|
27
27
|
fs.readdirSync(commonBuildPath).forEach(file => {
|
|
28
|
+
// Never distribute or overwrite app-owned screenshot data.
|
|
29
|
+
if (file === "scripts-screenshot") return;
|
|
28
30
|
const sourcePath = path.join(commonBuildPath, file);
|
|
29
31
|
const destPath = path.join(projectRoot, file);
|
|
30
32
|
|
package/scripts/uninstall.js
CHANGED
|
@@ -70,7 +70,8 @@ filesInProject.forEach(file => {
|
|
|
70
70
|
if (fs.existsSync(commonBuildPath)) {
|
|
71
71
|
fs.readdirSync(commonBuildPath).forEach(file => {
|
|
72
72
|
const destPath = path.join(projectRoot, file);
|
|
73
|
-
|
|
73
|
+
// Screenshot data belongs to the app, including folders from older releases.
|
|
74
|
+
if (file === "scripts" || file === "scripts-screenshot" || isAgentInstructionAsset(file)) {
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
76
77
|
if (fs.existsSync(destPath)) {
|
|
@@ -88,6 +89,19 @@ if (fs.existsSync(commonBuildPath)) {
|
|
|
88
89
|
});
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
for (const helperDirectory of [
|
|
93
|
+
path.join(projectRoot, "scripts", "screenshot"),
|
|
94
|
+
path.join(projectRoot, "scripts-screenshot", "screenshot")
|
|
95
|
+
]) {
|
|
96
|
+
for (const helperName of ["frame-samples.js", "background-decorations.js"]) {
|
|
97
|
+
const helperPath = path.join(helperDirectory, helperName);
|
|
98
|
+
if (fs.existsSync(helperPath)) {
|
|
99
|
+
fs.unlinkSync(helperPath);
|
|
100
|
+
process.stdout.write(`🗑️ Removed file: ${helperPath}\n`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
91
105
|
if (fs.existsSync(baselineProfileSetupScript)) {
|
|
92
106
|
try {
|
|
93
107
|
fs.unlinkSync(baselineProfileSetupScript);
|