mosaic-headless 1.30.0 → 1.30.1
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/SKILL.md +4 -4
- package/assets/templates/platforms/claude-ai.json +1 -1
- package/assets/templates/platforms/claude-code.json +1 -1
- package/assets/templates/platforms/codex-cli.json +1 -1
- package/assets/templates/platforms/copilot.json +1 -1
- package/assets/templates/platforms/gemini-cli.json +1 -1
- package/data/browser-verification/moksa.csv +3986 -0
- package/data/browser-verification/my-account.csv +148 -0
- package/data/node-properties.csv +2 -2
- package/package.json +2 -1
- package/scripts/check-release.mjs +34 -5
- package/tools/extract_default_children.py +1 -1
- package/tools/extract_node_types.py +1 -1
- package/tools/verify_browser.py +20 -8
- package/tools/verify_conversion.py +6 -2
- package/data/browser-verification.csv +0 -4133
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
breakpoint,attrID,property,declared,computed,status
|
|
2
|
+
_,mk-acct-body,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
3
|
+
_,mk-acct-body,paddingLeft,40px,40px,ok
|
|
4
|
+
_,mk-acct-body,paddingRight,40px,40px,ok
|
|
5
|
+
_,mk-acct-body,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
6
|
+
_,mk-acct-body-in,width,100%,viewport- or parent-relative,not-comparable
|
|
7
|
+
_,mk-acct-body-in,maxWidth,1240px,1240px,ok
|
|
8
|
+
_,mk-acct-body-in,marginLeft,auto,auto resolves to a used value (60px),not-comparable
|
|
9
|
+
_,mk-acct-body-in,marginRight,auto,auto resolves to a used value (60px),not-comparable
|
|
10
|
+
_,mk-acct-head,display,grid,grid,ok
|
|
11
|
+
_,mk-acct-head,gridCols,84px 1fr,84px 1156px,ok
|
|
12
|
+
_,mk-acct-head,columnGap,0px,0px,ok
|
|
13
|
+
_,mk-acct-head,alignItems,start,start,ok
|
|
14
|
+
_,mk-acct-head,paddingTop,22px,22px,ok
|
|
15
|
+
_,mk-acct-head,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
16
|
+
_,mk-acct-mast,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
17
|
+
_,mk-acct-mast,paddingLeft,40px,40px,ok
|
|
18
|
+
_,mk-acct-mast,paddingRight,40px,40px,ok
|
|
19
|
+
_,mk-acct-mast,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
20
|
+
_,mk-acct-mast-in,width,100%,viewport- or parent-relative,not-comparable
|
|
21
|
+
_,mk-acct-mast-in,maxWidth,1240px,1240px,ok
|
|
22
|
+
_,mk-acct-mast-in,marginLeft,auto,auto resolves to a used value (60px),not-comparable
|
|
23
|
+
_,mk-acct-mast-in,marginRight,auto,auto resolves to a used value (60px),not-comparable
|
|
24
|
+
_,mk-acct-pad,paddingTop,70px,70px,ok
|
|
25
|
+
_,mk-acct-pad,paddingBottom,48px,48px,ok
|
|
26
|
+
_,mk-acct-r-0,display,grid,grid,ok
|
|
27
|
+
_,mk-acct-r-0,gridCols,150px 1fr,150px 986px,ok
|
|
28
|
+
_,mk-acct-r-0,columnGap,20px,20px,ok
|
|
29
|
+
_,mk-acct-r-0,alignItems,baseline,baseline,ok
|
|
30
|
+
_,mk-acct-r-0,paddingTop,13px,13px,ok
|
|
31
|
+
_,mk-acct-r-0,paddingBottom,13px,13px,ok
|
|
32
|
+
_,mk-acct-r-0,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
33
|
+
_,mk-acct-r-1,display,grid,grid,ok
|
|
34
|
+
_,mk-acct-r-1,gridCols,150px 1fr,150px 986px,ok
|
|
35
|
+
_,mk-acct-r-1,columnGap,20px,20px,ok
|
|
36
|
+
_,mk-acct-r-1,alignItems,baseline,baseline,ok
|
|
37
|
+
_,mk-acct-r-1,paddingTop,13px,13px,ok
|
|
38
|
+
_,mk-acct-r-1,paddingBottom,13px,13px,ok
|
|
39
|
+
_,mk-acct-r-1,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
40
|
+
_,mk-acct-r-2,display,grid,grid,ok
|
|
41
|
+
_,mk-acct-r-2,gridCols,150px 1fr,150px 986px,ok
|
|
42
|
+
_,mk-acct-r-2,columnGap,20px,20px,ok
|
|
43
|
+
_,mk-acct-r-2,alignItems,baseline,baseline,ok
|
|
44
|
+
_,mk-acct-r-2,paddingTop,13px,13px,ok
|
|
45
|
+
_,mk-acct-r-2,paddingBottom,13px,13px,ok
|
|
46
|
+
_,mk-acct-r-2,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
47
|
+
_,mk-acct-rows,marginTop,30px,30px,ok
|
|
48
|
+
_,mk-acct-rows,display,grid,grid,ok
|
|
49
|
+
_,mk-acct-rows,rowGap,0px,0px,ok
|
|
50
|
+
_,mk-acct-sheet,paddingBottom,120px,120px,ok
|
|
51
|
+
_t,mk-acct-body,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
52
|
+
_t,mk-acct-body,paddingLeft,28px,28px,ok
|
|
53
|
+
_t,mk-acct-body,paddingRight,28px,28px,ok
|
|
54
|
+
_t,mk-acct-body,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
55
|
+
_t,mk-acct-body-in,width,100%,viewport- or parent-relative,not-comparable
|
|
56
|
+
_t,mk-acct-body-in,maxWidth,1240px,1240px,ok
|
|
57
|
+
_t,mk-acct-body-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
|
|
58
|
+
_t,mk-acct-body-in,marginRight,auto,auto resolves to a used value (0px),not-comparable
|
|
59
|
+
_t,mk-acct-head,display,grid,grid,ok
|
|
60
|
+
_t,mk-acct-head,gridCols,84px 1fr,84px 760px,ok
|
|
61
|
+
_t,mk-acct-head,columnGap,0px,0px,ok
|
|
62
|
+
_t,mk-acct-head,alignItems,start,start,ok
|
|
63
|
+
_t,mk-acct-head,paddingTop,22px,22px,ok
|
|
64
|
+
_t,mk-acct-head,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
65
|
+
_t,mk-acct-mast,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
66
|
+
_t,mk-acct-mast,paddingLeft,28px,28px,ok
|
|
67
|
+
_t,mk-acct-mast,paddingRight,28px,28px,ok
|
|
68
|
+
_t,mk-acct-mast,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
69
|
+
_t,mk-acct-mast-in,width,100%,viewport- or parent-relative,not-comparable
|
|
70
|
+
_t,mk-acct-mast-in,maxWidth,1240px,1240px,ok
|
|
71
|
+
_t,mk-acct-mast-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
|
|
72
|
+
_t,mk-acct-mast-in,marginRight,auto,auto resolves to a used value (0px),not-comparable
|
|
73
|
+
_t,mk-acct-pad,paddingTop,50px,50px,ok
|
|
74
|
+
_t,mk-acct-pad,paddingBottom,48px,48px,ok
|
|
75
|
+
_t,mk-acct-r-0,display,grid,grid,ok
|
|
76
|
+
_t,mk-acct-r-0,gridCols,150px 1fr,150px 590px,ok
|
|
77
|
+
_t,mk-acct-r-0,columnGap,20px,20px,ok
|
|
78
|
+
_t,mk-acct-r-0,alignItems,baseline,baseline,ok
|
|
79
|
+
_t,mk-acct-r-0,paddingTop,13px,13px,ok
|
|
80
|
+
_t,mk-acct-r-0,paddingBottom,13px,13px,ok
|
|
81
|
+
_t,mk-acct-r-0,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
82
|
+
_t,mk-acct-r-1,display,grid,grid,ok
|
|
83
|
+
_t,mk-acct-r-1,gridCols,150px 1fr,150px 590px,ok
|
|
84
|
+
_t,mk-acct-r-1,columnGap,20px,20px,ok
|
|
85
|
+
_t,mk-acct-r-1,alignItems,baseline,baseline,ok
|
|
86
|
+
_t,mk-acct-r-1,paddingTop,13px,13px,ok
|
|
87
|
+
_t,mk-acct-r-1,paddingBottom,13px,13px,ok
|
|
88
|
+
_t,mk-acct-r-1,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
89
|
+
_t,mk-acct-r-2,display,grid,grid,ok
|
|
90
|
+
_t,mk-acct-r-2,gridCols,150px 1fr,150px 590px,ok
|
|
91
|
+
_t,mk-acct-r-2,columnGap,20px,20px,ok
|
|
92
|
+
_t,mk-acct-r-2,alignItems,baseline,baseline,ok
|
|
93
|
+
_t,mk-acct-r-2,paddingTop,13px,13px,ok
|
|
94
|
+
_t,mk-acct-r-2,paddingBottom,13px,13px,ok
|
|
95
|
+
_t,mk-acct-r-2,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
96
|
+
_t,mk-acct-rows,marginTop,30px,30px,ok
|
|
97
|
+
_t,mk-acct-rows,display,grid,grid,ok
|
|
98
|
+
_t,mk-acct-rows,rowGap,0px,0px,ok
|
|
99
|
+
_t,mk-acct-sheet,paddingBottom,120px,120px,ok
|
|
100
|
+
_m,mk-acct-body,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
101
|
+
_m,mk-acct-body,paddingLeft,18px,18px,ok
|
|
102
|
+
_m,mk-acct-body,paddingRight,18px,18px,ok
|
|
103
|
+
_m,mk-acct-body,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
104
|
+
_m,mk-acct-body-in,width,100%,viewport- or parent-relative,not-comparable
|
|
105
|
+
_m,mk-acct-body-in,maxWidth,1240px,1240px,ok
|
|
106
|
+
_m,mk-acct-body-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
|
|
107
|
+
_m,mk-acct-body-in,marginRight,auto,auto resolves to a used value (0px),not-comparable
|
|
108
|
+
_m,mk-acct-head,display,grid,grid,ok
|
|
109
|
+
_m,mk-acct-head,gridCols,48px 1fr,48px 306px,ok
|
|
110
|
+
_m,mk-acct-head,columnGap,0px,0px,ok
|
|
111
|
+
_m,mk-acct-head,alignItems,start,start,ok
|
|
112
|
+
_m,mk-acct-head,paddingTop,22px,22px,ok
|
|
113
|
+
_m,mk-acct-head,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
114
|
+
_m,mk-acct-mast,backgroundColor,"rgb(250,250,247)","rgb(250, 250, 247)",ok
|
|
115
|
+
_m,mk-acct-mast,paddingLeft,18px,18px,ok
|
|
116
|
+
_m,mk-acct-mast,paddingRight,18px,18px,ok
|
|
117
|
+
_m,mk-acct-mast,fontFamily,"'Noto Sans TC','PingFang TC','Hiragino Sans TC','Microsoft JhengHei',sans-serif","""Noto Sans TC"", ""PingFang TC"", ""Hiragino Sans TC"", ""Microsoft JhengHei"", sans-serif",ok
|
|
118
|
+
_m,mk-acct-mast-in,width,100%,viewport- or parent-relative,not-comparable
|
|
119
|
+
_m,mk-acct-mast-in,maxWidth,1240px,1240px,ok
|
|
120
|
+
_m,mk-acct-mast-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
|
|
121
|
+
_m,mk-acct-mast-in,marginRight,auto,auto resolves to a used value (0px),not-comparable
|
|
122
|
+
_m,mk-acct-pad,paddingTop,24px,24px,ok
|
|
123
|
+
_m,mk-acct-pad,paddingBottom,34px,34px,ok
|
|
124
|
+
_m,mk-acct-r-0,display,grid,grid,ok
|
|
125
|
+
_m,mk-acct-r-0,gridCols,84px 1fr,84px 210px,ok
|
|
126
|
+
_m,mk-acct-r-0,columnGap,12px,12px,ok
|
|
127
|
+
_m,mk-acct-r-0,alignItems,baseline,baseline,ok
|
|
128
|
+
_m,mk-acct-r-0,paddingTop,13px,13px,ok
|
|
129
|
+
_m,mk-acct-r-0,paddingBottom,13px,13px,ok
|
|
130
|
+
_m,mk-acct-r-0,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
131
|
+
_m,mk-acct-r-1,display,grid,grid,ok
|
|
132
|
+
_m,mk-acct-r-1,gridCols,84px 1fr,84px 210px,ok
|
|
133
|
+
_m,mk-acct-r-1,columnGap,12px,12px,ok
|
|
134
|
+
_m,mk-acct-r-1,alignItems,baseline,baseline,ok
|
|
135
|
+
_m,mk-acct-r-1,paddingTop,13px,13px,ok
|
|
136
|
+
_m,mk-acct-r-1,paddingBottom,13px,13px,ok
|
|
137
|
+
_m,mk-acct-r-1,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
138
|
+
_m,mk-acct-r-2,display,grid,grid,ok
|
|
139
|
+
_m,mk-acct-r-2,gridCols,84px 1fr,84px 210px,ok
|
|
140
|
+
_m,mk-acct-r-2,columnGap,12px,12px,ok
|
|
141
|
+
_m,mk-acct-r-2,alignItems,baseline,baseline,ok
|
|
142
|
+
_m,mk-acct-r-2,paddingTop,13px,13px,ok
|
|
143
|
+
_m,mk-acct-r-2,paddingBottom,13px,13px,ok
|
|
144
|
+
_m,mk-acct-r-2,customDeclarations:border-top,"1px solid rgba(22,24,28,.16)",no computed value,not-comparable
|
|
145
|
+
_m,mk-acct-rows,marginTop,30px,30px,ok
|
|
146
|
+
_m,mk-acct-rows,display,grid,grid,ok
|
|
147
|
+
_m,mk-acct-rows,rowGap,0px,0px,ok
|
|
148
|
+
_m,mk-acct-sheet,paddingBottom,72px,72px,ok
|
package/data/node-properties.csv
CHANGED
|
@@ -60,7 +60,7 @@ WPMenuElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,me
|
|
|
60
60
|
NavbarElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,buttonBreakpoint,ValidateAllowUndefined|ValidatorAcceptedValues|ValidatorBreakpoint|Validators,none,true,,data-animation|data-toggle-breakpoint-id,Mosaic/NodeTypes/Navbar/NavbarElementMResourceData.php
|
|
61
61
|
NavbarElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,animation,ValidateAllowUndefined|ValidatorAcceptedValues|Validators,none|fade|fadeDown|fadeUp|scaleDown|flipDown,true,,data-animation|data-toggle-breakpoint-id,Mosaic/NodeTypes/Navbar/NavbarElementMResourceData.php
|
|
62
62
|
NavbarElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,disableScroll,ValidateAllowUndefined|ValidatorAcceptedValues|Validators,0|1,true,,data-animation|data-toggle-breakpoint-id,Mosaic/NodeTypes/Navbar/NavbarElementMResourceData.php
|
|
63
|
-
NodeMResourceDataAbstract,MResourceDataAbstract,free,createDataSimple,currentStatus,ValidatorAcceptedValues
|
|
63
|
+
NodeMResourceDataAbstract,MResourceDataAbstract,free,createDataSimple,currentStatus,ValidatorAcceptedValues,PUBLISH|DELETE,,,,Mosaic/NodeTypes/NodeAbstract/NodeMResourceDataAbstract.php
|
|
64
64
|
NodeMResourceDataAbstract,MResourceDataAbstract,free,createDataGroup,override,,,true,,,Mosaic/NodeTypes/NodeAbstract/NodeMResourceDataAbstract.php
|
|
65
65
|
OpenStreetMapElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,latitude,ValidateAllowUndefined|ValidatorDynamicCodeObject|ValidatorFloat|ValidatorFloatAsString|Validators,,true,,,Mosaic/NodeTypes/OpenStreetMap/OpenStreetMapElementMResourceData.php
|
|
66
66
|
OpenStreetMapElementMResourceData,ElementMResourceDataAbstract,free,createDataSimple,longitude,ValidateAllowUndefined|ValidatorDynamicCodeObject|ValidatorFloat|ValidatorFloatAsString|Validators,,true,,,Mosaic/NodeTypes/OpenStreetMap/OpenStreetMapElementMResourceData.php
|
|
@@ -134,7 +134,7 @@ SliderElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,aut
|
|
|
134
134
|
SliderElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,isCarousel,ValidateAllowUndefined|ValidatorAcceptedValues|Validators,0|1,true,,data-animation-type|data-duration|data-easing|data-autoplay|data-autoplay-delay|data-autoplay-limit|data-carousel|data-default-slide-index|data-slide-label|role|aria-roledescription,Mosaic/NodeTypes/Pro/Slider/SliderElementMResourceData.php
|
|
135
135
|
SliderElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,defaultSlideIndex,ValidateAllowUndefined|ValidatorInteger|ValidatorIntegerAsString|Validators,,true,,data-animation-type|data-duration|data-easing|data-autoplay|data-autoplay-delay|data-autoplay-limit|data-carousel|data-default-slide-index|data-slide-label|role|aria-roledescription,Mosaic/NodeTypes/Pro/Slider/SliderElementMResourceData.php
|
|
136
136
|
SliderElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,ariaLabel,ValidateAllowUndefined|ValidatorString|Validators,,true,,data-animation-type|data-duration|data-easing|data-autoplay|data-autoplay-delay|data-autoplay-limit|data-carousel|data-default-slide-index|data-slide-label|role|aria-roledescription,Mosaic/NodeTypes/Pro/Slider/SliderElementMResourceData.php
|
|
137
|
-
SliderSlideElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,image,ValidateAllowUndefined|ValidatorAcceptedValues|ValidatorDynamicCodeObject|ValidatorImageAttachment|ValidatorURL|Validators
|
|
137
|
+
SliderSlideElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,image,ValidateAllowUndefined|ValidatorAcceptedValues|ValidatorDynamicCodeObject|ValidatorImageAttachment|ValidatorURL|Validators,MosaicDefaultURL,true,,,Mosaic/NodeTypes/Pro/Slider/SliderSlides/SliderSlide/SliderSlideElementMResourceData.php
|
|
138
138
|
SliderSlideElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,positionX,ValidateAllowUndefined|ValidatorStyleBackground|ValidatorStyleBackgroundPosition|Validators,,true,,,Mosaic/NodeTypes/Pro/Slider/SliderSlides/SliderSlide/SliderSlideElementMResourceData.php
|
|
139
139
|
SliderSlideElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,positionY,ValidateAllowUndefined|ValidatorStyleBackground|ValidatorStyleBackgroundPosition|Validators,,true,,,Mosaic/NodeTypes/Pro/Slider/SliderSlides/SliderSlide/SliderSlideElementMResourceData.php
|
|
140
140
|
SliderSlideElementMResourceData,ElementMResourceDataAbstract,pro,createDataSimple,alt,ValidateAllowUndefined|ValidatorDynamicCodeObject|ValidatorString|Validators,,true,,,Mosaic/NodeTypes/Pro/Slider/SliderSlides/SliderSlide/SliderSlideElementMResourceData.php
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mosaic-headless",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.1",
|
|
4
4
|
"description": "AI-agent skill: build Mosaic Pro (Nextend) WordPress sites by writing the underlying data model directly - 23 custom tables, no visual editor, no DOM. Every node type, style property and node property swept against a live install and asserted on the delivered HTML and compiled CSS. Installs into Claude Code, Cursor, Codex CLI, Gemini CLI, Copilot, Continue, Windsurf and Claude.ai.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wordpress",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"scripts/",
|
|
34
34
|
"assets/",
|
|
35
35
|
"data/*.csv",
|
|
36
|
+
"data/browser-verification/*.csv",
|
|
36
37
|
"references/",
|
|
37
38
|
"sites/_moksa.py",
|
|
38
39
|
"sites/_components.py",
|
|
@@ -26,9 +26,37 @@ import { fileURLToPath } from "node:url";
|
|
|
26
26
|
|
|
27
27
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
28
28
|
const read = (p) => fs.readFileSync(path.join(ROOT, p), "utf8");
|
|
29
|
+
// A table split one file per page (data/browser-verification/) is still one table:
|
|
30
|
+
// its CSVs, in name order, each with its own header.
|
|
31
|
+
const tableFiles = (p) => fs.statSync(path.join(ROOT, p)).isDirectory()
|
|
32
|
+
? fs.readdirSync(path.join(ROOT, p)).filter((f) => f.endsWith(".csv")).sort()
|
|
33
|
+
.map((f) => `${p}/${f}`)
|
|
34
|
+
: [p];
|
|
29
35
|
const problems = [];
|
|
30
36
|
const fail = (m) => problems.push(m);
|
|
31
37
|
|
|
38
|
+
// ---------- the plugin directory's limits -----------------------------------
|
|
39
|
+
//
|
|
40
|
+
// The Claude plugin directory reads the repository root, every tracked file of it,
|
|
41
|
+
// and holds a submission for a reviewer when any file that is not an image or font
|
|
42
|
+
// is over 256 KiB, or when there are more than 512 files. A 400 KB CSV and a 2 MB
|
|
43
|
+
// generated site file did exactly that. Checked here, so it fails on this machine
|
|
44
|
+
// rather than in a review queue a week later.
|
|
45
|
+
try {
|
|
46
|
+
const tracked = execSync("git ls-files -z", { cwd: ROOT }).toString().split("\0").filter(Boolean);
|
|
47
|
+
if (tracked.length > 512) fail(`${tracked.length} tracked files - the plugin directory allows 512`);
|
|
48
|
+
for (const f of tracked) {
|
|
49
|
+
if (/\.(png|jpe?g|gif|webp|svg|ico|woff2?|ttf|otf)$/i.test(f)) continue;
|
|
50
|
+
const full = path.join(ROOT, f);
|
|
51
|
+
if (!fs.existsSync(full)) continue;
|
|
52
|
+
const size = fs.statSync(full).size;
|
|
53
|
+
if (size > 256 * 1024)
|
|
54
|
+
fail(`${f} is ${(size / 1024).toFixed(0)} KiB - the plugin directory holds any non-image file over 256 KiB`);
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
// not a git checkout (an unpacked tarball): nothing to measure against
|
|
58
|
+
}
|
|
59
|
+
|
|
32
60
|
// ---------- versions agree --------------------------------------------------
|
|
33
61
|
|
|
34
62
|
const pkg = JSON.parse(read("package.json"));
|
|
@@ -91,13 +119,14 @@ if (!fs.existsSync(path.join(ROOT, pkg.bin["mosaic-headless"])))
|
|
|
91
119
|
|
|
92
120
|
// ---------- the numbers in the docs are counted, not trusted ----------------
|
|
93
121
|
|
|
94
|
-
const rows = (p) =>
|
|
122
|
+
const rows = (p) => tableFiles(p)
|
|
123
|
+
.reduce((n, f) => n + read(f).trim().split("\n").length - 1, 0); // minus each header
|
|
95
124
|
const counts = {
|
|
96
125
|
"data/node-verification.csv": 126,
|
|
97
126
|
"data/style-verification.csv": 98,
|
|
98
127
|
"data/node-property-verification.csv": 191,
|
|
99
128
|
"data/rwd-verification.csv": 733,
|
|
100
|
-
"data/browser-verification
|
|
129
|
+
"data/browser-verification": 4132,
|
|
101
130
|
"data/style-state-verification.csv": 52,
|
|
102
131
|
"data/interaction-verification.csv": 7,
|
|
103
132
|
"data/data-class-hierarchy.csv": 125,
|
|
@@ -131,7 +160,7 @@ if (!style.includes("SKIPPED")) fail("style-verification.csv has no SKIPPED rows
|
|
|
131
160
|
|
|
132
161
|
// The browser pass has the same obligation, under a different word: a declaration it
|
|
133
162
|
// cannot soundly compare must say so rather than be counted as agreement.
|
|
134
|
-
const browser =
|
|
163
|
+
const browser = tableFiles("data/browser-verification").map(read).join("\n");
|
|
135
164
|
if (!browser.includes("not-comparable"))
|
|
136
165
|
fail("browser-verification.csv has no not-comparable rows - a computed-value check "
|
|
137
166
|
+ "that claims to compare everything is comparing things it cannot");
|
|
@@ -190,13 +219,13 @@ if (/,FAIL,/.test(zip)) fail("data/theme-zip-verification.csv carries a failed c
|
|
|
190
219
|
// rwd and browser counts, and must not carry the previous ones.
|
|
191
220
|
{
|
|
192
221
|
const fmt = (n) => n.toLocaleString("en-US");
|
|
193
|
-
const want = [rows("data/rwd-verification.csv"), rows("data/browser-verification
|
|
222
|
+
const want = [rows("data/rwd-verification.csv"), rows("data/browser-verification")];
|
|
194
223
|
for (const readme of ["README.md", "README.zh-TW.md", "README.ja.md", "README.ko.md"]) {
|
|
195
224
|
const text = read(readme);
|
|
196
225
|
for (const n of want)
|
|
197
226
|
if (!text.includes(fmt(n)) && !text.includes(String(n)))
|
|
198
227
|
fail(`${readme} does not quote ${fmt(n)} - it is quoting a stale count`);
|
|
199
|
-
if (
|
|
228
|
+
if (/\b0 findings\b|指摘 0 件|지적 0건|0 項發現/.test(text))
|
|
200
229
|
fail(`${readme} still claims a design audit with 0 findings`);
|
|
201
230
|
}
|
|
202
231
|
}
|
|
@@ -100,7 +100,7 @@ def extract(plugin_root, out_dir):
|
|
|
100
100
|
# ---- and the ones a type heals into itself
|
|
101
101
|
stem_by_class = {}
|
|
102
102
|
for path, src in files:
|
|
103
|
-
m = re.search(r"class\s+(\w+)ElementTypeFactory
|
|
103
|
+
m = re.search(r"class\s+(\w+)ElementTypeFactory\b", src)
|
|
104
104
|
if m:
|
|
105
105
|
stem_by_class[m.group(1)] = stem_to_slug.get(m.group(1), "")
|
|
106
106
|
|
|
@@ -154,7 +154,7 @@ def extract(plugin_root, out_dir):
|
|
|
154
154
|
accepted = []
|
|
155
155
|
if acc:
|
|
156
156
|
accepted = re.findall(r"'([^']+)'", acc.group(1))
|
|
157
|
-
accepted += [c for c in re.findall(r"
|
|
157
|
+
accepted += [c for c in re.findall(r"\b\w+::(\w+)\b", acc.group(1))]
|
|
158
158
|
props.append(
|
|
159
159
|
{
|
|
160
160
|
"owner_class": owner,
|
package/tools/verify_browser.py
CHANGED
|
@@ -213,7 +213,7 @@ def tidy(text):
|
|
|
213
213
|
report every hairline on the page as overridden."""
|
|
214
214
|
t = re.sub(r"\s*,\s*", ",", (text or "").strip().lower())
|
|
215
215
|
t = re.sub(r"\s+", " ", t)
|
|
216
|
-
return re.sub(r"(?<![\d.])\.(\d)", r"0
|
|
216
|
+
return re.sub(r"(?<![\d.])\.(\d)", r"0.\1", t)
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
# The comparison knows properties by their Mosaic key, but customDeclarations hands it raw
|
|
@@ -609,7 +609,8 @@ def main():
|
|
|
609
609
|
ap.add_argument("--config",
|
|
610
610
|
help="JSON with base/cookie/nonce; omit it and the MOSAIC_SITE_URL / MOSAIC_REST_COOKIE / MOSAIC_REST_NONCE environment variables supply them instead")
|
|
611
611
|
ap.add_argument("--site", required=True)
|
|
612
|
-
ap.add_argument("--csv", help="the computed-value table"
|
|
612
|
+
ap.add_argument("--csv", help="a DIRECTORY: the computed-value table is "
|
|
613
|
+
"written one file per page, <dir>/<slug>.csv")
|
|
613
614
|
ap.add_argument("--audit", help="the design-audit findings")
|
|
614
615
|
ap.add_argument("--ack", default=os.path.join(
|
|
615
616
|
os.path.dirname(os.path.abspath(__file__)), "..", "data",
|
|
@@ -754,13 +755,24 @@ def main():
|
|
|
754
755
|
# count in the release gate - should not have to find the blank line between them.
|
|
755
756
|
# The audit file is written even when it is empty: a header with no rows says
|
|
756
757
|
# "this ran and found nothing", where a missing file says nothing at all.
|
|
758
|
+
#
|
|
759
|
+
# The computed-value table is one file per page, named by its slug, with no url
|
|
760
|
+
# column: a single file carried the site's address 4,000 times over and passed
|
|
761
|
+
# the plugin directory's 256 KiB per-file limit. The slug is the filename, and
|
|
762
|
+
# the address is whatever --config pointed at.
|
|
757
763
|
if a.csv:
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
+
os.makedirs(a.csv, exist_ok=True)
|
|
765
|
+
per_page = {}
|
|
766
|
+
for r in rows:
|
|
767
|
+
per_page.setdefault(r[0].rstrip("/").rsplit("/", 1)[-1], []).append(r[1:])
|
|
768
|
+
for slug, page_rows in per_page.items():
|
|
769
|
+
out = os.path.join(a.csv, slug + ".csv")
|
|
770
|
+
with open(out, "w", newline="", encoding="utf-8") as fh:
|
|
771
|
+
w = csv.writer(fh)
|
|
772
|
+
w.writerow(["breakpoint", "attrID", "property", "declared",
|
|
773
|
+
"computed", "status"])
|
|
774
|
+
w.writerows(page_rows)
|
|
775
|
+
print("\nwrote %s (%d rows)" % (out, len(page_rows)))
|
|
764
776
|
if a.audit:
|
|
765
777
|
with open(a.audit, "w", newline="", encoding="utf-8") as fh:
|
|
766
778
|
w = csv.writer(fh)
|
|
@@ -29,6 +29,7 @@ import argparse
|
|
|
29
29
|
import csv
|
|
30
30
|
import html as htmllib
|
|
31
31
|
import json
|
|
32
|
+
import os
|
|
32
33
|
import re
|
|
33
34
|
import sys
|
|
34
35
|
import time
|
|
@@ -129,7 +130,7 @@ def main():
|
|
|
129
130
|
ap.add_argument("--report", help="the CSV from_elementor.py wrote")
|
|
130
131
|
ap.add_argument("--csv")
|
|
131
132
|
ap.add_argument("--width", type=int, default=1440)
|
|
132
|
-
ap.add_argument("--browser", help="browser-verification CSV from verify_browser.py")
|
|
133
|
+
ap.add_argument("--browser", help="browser-verification CSV, or the per-page directory, from verify_browser.py")
|
|
133
134
|
ap.add_argument("--audit", help="design-audit CSV from verify_browser.py")
|
|
134
135
|
ap.add_argument("--rwd", help="rwd-verification CSV from verify_rwd.py")
|
|
135
136
|
ap.add_argument("--prefix", default="el",
|
|
@@ -230,7 +231,10 @@ def main():
|
|
|
230
231
|
"own media query" % len(rr) if not bad else
|
|
231
232
|
"%d of %d not verified" % (len(bad), len(rr)))
|
|
232
233
|
if a.browser:
|
|
233
|
-
|
|
234
|
+
# a file, or the per-page directory verify_browser.py writes
|
|
235
|
+
files = ([os.path.join(a.browser, f) for f in sorted(os.listdir(a.browser))
|
|
236
|
+
if f.endswith(".csv")] if os.path.isdir(a.browser) else [a.browser])
|
|
237
|
+
br = [r for f in files for r in csv.DictReader(open(f, encoding="utf-8"))]
|
|
234
238
|
ok = sum(1 for r in br if r.get("status") == "ok")
|
|
235
239
|
over = [r for r in br if r.get("status") == "OVERRIDDEN"]
|
|
236
240
|
check("COMPUTED", bool(br) and not over,
|