@freeappstore/compliance 0.7.19 → 0.7.20

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 CHANGED
@@ -24,6 +24,29 @@ for (const r of results) {
24
24
  | `PWA manifest` | `web/public/manifest.json` exists and has name / short_name / start_url / display | warn |
25
25
  | `Bundle size` | Initial-load JS (entry + static imports) ≤ 300 KB gzipped; lazy wasm/workers/dynamic chunks ≤ 25 MB each | **fail** if either cap is exceeded; warn if not built yet |
26
26
 
27
+ ## Styling checks (warn-only rollout, #324)
28
+
29
+ - `CSS discipline`: PostCSS parses `web/src/**/*.css` and reports banned token
30
+ aliases, unlayered rules, hex colours outside token blocks, per-screen dark
31
+ overrides, and more than 15 feature classes per stylesheet.
32
+ - `No excessive inline styles`: vendored from FreeGameStore's platform check;
33
+ warns above 15 `style={{...}}` objects per TSX file or 30 total. Tests and
34
+ comments are excluded. FAS permits genuinely dynamic values with a reason
35
+ commented beside them; static appearance belongs in Tailwind on FAS tokens.
36
+ - `Opaque surfaces`: warns for alpha colours in `--paper`, `--panel`, or
37
+ `--popover`, in either theme. `--panel-glass` and `--scrim` are exempt.
38
+
39
+ `fas check --json` includes these warnings without failing the app build.
40
+ `pnpm lint:platform-ui` reuses all three checks for SDK UI, Console, and Admin,
41
+ and reports parsed TSX inline-style and runtime CSS injection counts. CI stays
42
+ in warn-only migration mode while #322 is pending. After migration, run
43
+ `pnpm lint:platform-ui --strict` to fail on runtime CSS injection or inline
44
+ styles without a nearby comment explaining the dynamic value.
45
+
46
+ The PAS CSS source referenced by #324 was unavailable (404); its five specified
47
+ rules are implemented here with PostCSS. The FGS inline scanner is adapted from
48
+ `freegamestore-online/platform/packages/compliance/src/checks/no-excessive-inline-styles.ts`.
49
+
27
50
  ## License
28
51
 
29
52
  MIT.
@@ -0,0 +1,5 @@
1
+ import type { FileSource } from '../lib/file-source.js';
2
+ import type { CheckResult } from '../types.js';
3
+ /** #324: warn-only CSS structure checks, parsed with PostCSS. */
4
+ export declare function checkCssDiscipline(source: FileSource): Promise<CheckResult>;
5
+ //# sourceMappingURL=css-discipline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-discipline.d.ts","sourceRoot":"","sources":["../../src/checks/css-discipline.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,iEAAiE;AACjE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CA8DjF"}
@@ -0,0 +1,65 @@
1
+ import { isTokenRule, stylesheets, within } from '../lib/styling.js';
2
+ /** #324: warn-only CSS structure checks, parsed with PostCSS. */
3
+ export async function checkCssDiscipline(source) {
4
+ const findings = [];
5
+ for await (const { path, root, error } of stylesheets(source)) {
6
+ if (!root) {
7
+ findings.push(`${path}: css-parse: ${error}`);
8
+ continue;
9
+ }
10
+ const classes = new Set();
11
+ root.walkRules((rule) => {
12
+ const token = isTokenRule(rule);
13
+ let print = false;
14
+ let keyframes = false;
15
+ let darkMedia = false;
16
+ for (let p = rule.parent; p; p = p.parent) {
17
+ if (p.type === 'atrule' && p.name === 'media' && /^print\b/.test(p.params))
18
+ print = true;
19
+ if (p.type === 'atrule' && /keyframes$/.test(p.name))
20
+ keyframes = true;
21
+ if (p.type === 'atrule' &&
22
+ p.name === 'media' &&
23
+ /prefers-color-scheme\s*:\s*dark/.test(p.params))
24
+ darkMedia = true;
25
+ }
26
+ const location = `${path}:${rule.source?.start?.line ?? 1}`;
27
+ if (!token && !within(rule, 'layer') && !within(rule, 'theme') && !print && !keyframes) {
28
+ findings.push(`${location}: unlayered-rule: ${rule.selector}`);
29
+ }
30
+ if (!token && (darkMedia || /(?:data-theme\s*=\s*["']?dark|\.dark\b)/.test(rule.selector))) {
31
+ findings.push(`${location}: per-screen-dark-override: ${rule.selector}`);
32
+ }
33
+ if (!token && !keyframes) {
34
+ for (const match of rule.selector.matchAll(/\.([\w-]+)/g))
35
+ classes.add(match[1]);
36
+ }
37
+ });
38
+ root.walkDecls((decl) => {
39
+ const location = `${path}:${decl.source?.start?.line ?? 1}`;
40
+ if (/^--(?:bg|surface|border|glass|dock|error)$/.test(decl.prop) ||
41
+ /var\(\s*--(?:bg|surface|border|glass|dock|error)(?=\s*[,)])/.test(decl.value)) {
42
+ findings.push(`${location}: banned-alias: ${decl.prop}: ${decl.value}`);
43
+ }
44
+ const token = decl.parent?.type === 'rule' && isTokenRule(decl.parent);
45
+ if (!token && /#[\da-f]{3,8}\b/i.test(decl.value)) {
46
+ findings.push(`${location}: hex-outside-tokens: ${decl.prop}`);
47
+ }
48
+ });
49
+ if (classes.size > 15)
50
+ findings.push(`${path}: feature-classes: ${classes.size} (threshold: 15)`);
51
+ }
52
+ return {
53
+ name: 'CSS discipline',
54
+ status: findings.length ? 'warn' : 'pass',
55
+ detail: findings.length ? findings.join('; ') : 'CSS follows the FAS styling standard',
56
+ ...(findings.length
57
+ ? {
58
+ suggestions: [
59
+ 'Use Tailwind on FAS tokens; keep custom rules in @layer base/components and colours in :root token blocks.',
60
+ ],
61
+ }
62
+ : {}),
63
+ };
64
+ }
65
+ //# sourceMappingURL=css-discipline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-discipline.js","sourceRoot":"","sources":["../../src/checks/css-discipline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FileSource } from '../lib/file-source.js';
2
+ import type { CheckResult } from '../types.js';
3
+ export declare function checkNoExcessiveInlineStyles(source: FileSource): Promise<CheckResult>;
4
+ //# sourceMappingURL=no-excessive-inline-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-excessive-inline-styles.d.ts","sourceRoot":"","sources":["../../src/checks/no-excessive-inline-styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA2B/C,wBAAsB,4BAA4B,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CA2D3F"}
@@ -0,0 +1,77 @@
1
+ import { stripCommentsAndStrings } from '../lib/strip.js';
2
+ /**
3
+ * Flags excessive use of React inline style objects (`style={{ ... }}`)
4
+ * in TSX files under web/src/. Some inline styles are fine — dynamic
5
+ * values, canvas positioning, animation transforms. But heavy reliance
6
+ * on `style={{` means the app isn't using Tailwind CSS or the
7
+ * design system, making theming and dark mode harder.
8
+ *
9
+ * Thresholds:
10
+ * - Any single file with > 15 inline style objects → warn
11
+ * - Total across all TSX files > 30 → warn
12
+ *
13
+ * Strips comments before scanning. Excludes test files.
14
+ *
15
+ * WARN level — guidelines, not a hard gate.
16
+ */
17
+ const PER_FILE_THRESHOLD = 15;
18
+ const TOTAL_THRESHOLD = 30;
19
+ const INLINE_STYLE_RE = /\bstyle\s*=\s*\{\{/g;
20
+ function isTestFile(path) {
21
+ return /\.(?:test|spec)\.[jt]sx?$/.test(path) || /(?:^|\/)(?:test|tests|__tests__)\//.test(path);
22
+ }
23
+ export async function checkNoExcessiveInlineStyles(source) {
24
+ let totalCount = 0;
25
+ const heavyFiles = [];
26
+ let fileCount = 0;
27
+ for await (const path of source.list()) {
28
+ if (!path.startsWith('web/src/'))
29
+ continue;
30
+ if (!path.endsWith('.tsx'))
31
+ continue;
32
+ if (isTestFile(path))
33
+ continue;
34
+ const raw = await source.read(path);
35
+ if (!raw)
36
+ continue;
37
+ const stripped = stripCommentsAndStrings(raw);
38
+ const matches = stripped.match(INLINE_STYLE_RE);
39
+ const count = matches ? matches.length : 0;
40
+ if (count > 0) {
41
+ totalCount += count;
42
+ fileCount++;
43
+ if (count > PER_FILE_THRESHOLD) {
44
+ heavyFiles.push({ file: path, count });
45
+ }
46
+ }
47
+ }
48
+ const perFileViolation = heavyFiles.length > 0;
49
+ const totalViolation = totalCount > TOTAL_THRESHOLD;
50
+ if (!perFileViolation && !totalViolation) {
51
+ return {
52
+ name: 'No excessive inline styles',
53
+ status: 'pass',
54
+ detail: `${totalCount} inline style(s) across ${fileCount} TSX file(s) (thresholds: ${PER_FILE_THRESHOLD}/file, ${TOTAL_THRESHOLD} total)`,
55
+ };
56
+ }
57
+ const parts = [];
58
+ if (totalViolation) {
59
+ parts.push(`${totalCount} total inline styles (threshold: ${TOTAL_THRESHOLD})`);
60
+ }
61
+ if (perFileViolation) {
62
+ parts.push(`${heavyFiles.length} file(s) exceed ${PER_FILE_THRESHOLD}/file: ${heavyFiles
63
+ .slice(0, 3)
64
+ .map((h) => `${h.file} (${h.count})`)
65
+ .join(', ')}${heavyFiles.length > 3 ? '...' : ''}`);
66
+ }
67
+ return {
68
+ name: 'No excessive inline styles',
69
+ status: 'warn',
70
+ detail: parts.join('; '),
71
+ suggestions: [
72
+ 'Replace inline style objects with Tailwind CSS utility classes where possible.',
73
+ 'FAS: keep only truly dynamic values (computed positions, transforms, progress widths) inline; comment the reason.',
74
+ ],
75
+ };
76
+ }
77
+ //# sourceMappingURL=no-excessive-inline-styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-excessive-inline-styles.js","sourceRoot":"","sources":["../../src/checks/no-excessive-inline-styles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FileSource } from '../lib/file-source.js';
2
+ import type { CheckResult } from '../types.js';
3
+ export declare function checkOpaqueSurface(source: FileSource): Promise<CheckResult>;
4
+ //# sourceMappingURL=opaque-surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opaque-surface.d.ts","sourceRoot":"","sources":["../../src/checks/opaque-surface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA2B/C,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAuBjF"}
@@ -0,0 +1,47 @@
1
+ import { stylesheets } from '../lib/styling.js';
2
+ function translucent(value) {
3
+ if (/\btransparent\b/i.test(value))
4
+ return true;
5
+ for (const match of value.matchAll(/#([\da-f]{8}|[\da-f]{4})\b/gi)) {
6
+ const hex = match[1].toLowerCase();
7
+ if (!hex.endsWith(hex.length === 4 ? 'f' : 'ff') &&
8
+ !hex.endsWith(hex.length === 4 ? 'F' : 'FF'))
9
+ return true;
10
+ }
11
+ for (const match of value.matchAll(/(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\(([^()]*)\)/gi)) {
12
+ const args = match[1];
13
+ const alpha = args.includes('/')
14
+ ? args.split('/').at(-1)
15
+ : args.split(',').length === 4
16
+ ? args.split(',').at(-1)
17
+ : undefined;
18
+ if (alpha !== undefined && Number.parseFloat(alpha) < (alpha.includes('%') ? 100 : 1))
19
+ return true;
20
+ }
21
+ return false;
22
+ }
23
+ export async function checkOpaqueSurface(source) {
24
+ const findings = [];
25
+ for await (const { path, root } of stylesheets(source)) {
26
+ root?.walkDecls((decl) => {
27
+ if (/^--(?:paper|panel|popover)$/.test(decl.prop) && translucent(decl.value)) {
28
+ findings.push(`${path}:${decl.source?.start?.line ?? 1}: ${decl.prop}: ${decl.value}`);
29
+ }
30
+ });
31
+ }
32
+ return {
33
+ name: 'Opaque surfaces',
34
+ status: findings.length ? 'warn' : 'pass',
35
+ detail: findings.length
36
+ ? findings.join('; ')
37
+ : '--paper, --panel and --popover have no translucent colours',
38
+ ...(findings.length
39
+ ? {
40
+ suggestions: [
41
+ 'Keep floating UI opaque in both themes; use --popover: var(--paper). Reserve glass effects for --panel-glass.',
42
+ ],
43
+ }
44
+ : {}),
45
+ };
46
+ }
47
+ //# sourceMappingURL=opaque-surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opaque-surface.js","sourceRoot":"","sources":["../../src/checks/opaque-surface.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,CAAC;QACnE,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;QACpC,IACE,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAC5C,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAE5C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,CAChC,6DAA6D,CAC9D,EAAE,CAAC;QACF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC9B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;gBAC5B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACxB,CAAC,CAAC,SAAS,CAAC;QAChB,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACnF,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAkB;IACzD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACvB,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7E,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACzF,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACzC,MAAM,EAAE,QAAQ,CAAC,MAAM;YACrB,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YACrB,CAAC,CAAC,4DAA4D;QAChE,GAAG,CAAC,QAAQ,CAAC,MAAM;YACjB,CAAC,CAAC;gBACE,WAAW,EAAE;oBACX,+GAA+G;iBAChH;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { checkBrandFonts } from './checks/brand-fonts.js';
2
2
  import { checkBrandTokens } from './checks/brand-tokens.js';
3
3
  import { checkBundleSize } from './checks/bundle-size.js';
4
4
  import { checkClaudeMdSlim } from './checks/claude-md-slim.js';
5
+ import { checkCssDiscipline } from './checks/css-discipline.js';
5
6
  import { checkDarkMode } from './checks/dark-mode.js';
6
7
  import { checkHtmlMeta } from './checks/html-meta.js';
7
8
  import { checkLicenseMit } from './checks/license-mit.js';
@@ -10,10 +11,12 @@ import { checkNoAds } from './checks/no-ads.js';
10
11
  import { checkNoBrandOverrides } from './checks/no-brand-overrides.js';
11
12
  import { checkNoCommittedArtifacts } from './checks/no-committed-artifacts.js';
12
13
  import { checkNoEnvProduction } from './checks/no-env-production.js';
14
+ import { checkNoExcessiveInlineStyles } from './checks/no-excessive-inline-styles.js';
13
15
  import { checkNoPayments } from './checks/no-payments.js';
14
16
  import { checkNoPlaceholders } from './checks/no-placeholders.js';
15
17
  import { checkNoScroll } from './checks/no-scroll.js';
16
18
  import { checkNoTracking } from './checks/no-tracking.js';
19
+ import { checkOpaqueSurface } from './checks/opaque-surface.js';
17
20
  import { checkPermissions } from './checks/permissions.js';
18
21
  import { checkMaskableIcon } from './checks/pwa-maskable-icon.js';
19
22
  import { checkPwaMeta } from './checks/pwa-meta.js';
@@ -34,7 +37,7 @@ export { detectPermissions, PERMISSION_IDS, readDeclaredPermissions, } from './l
34
37
  export type { LiveAuditInput, LiveAuditReport } from './live/index.js';
35
38
  export { auditLive, checkBrandFontsLive, checkBundleSizeLive, checkManifestLive, checkNoAdsLive, checkNoTrackingLive, checkUnsafeVhLive, } from './live/index.js';
36
39
  export type { CheckResult, CheckStatus } from './types.js';
37
- export { checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoAds, checkNoBrandOverrides, checkNoCommittedArtifacts, checkNoEnvProduction, checkNoPayments, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPermissions, checkPwaMeta, checkPwaOffline, checkStoreLink, checkTextSelectable, checkUnsafeVh, checkViewportSupport, fsFileSource, githubTreeSource, isGameProject, mapFileSource, };
40
+ export { checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkCssDiscipline, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoAds, checkNoBrandOverrides, checkNoCommittedArtifacts, checkNoEnvProduction, checkNoExcessiveInlineStyles, checkNoPayments, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkOpaqueSurface, checkPermissions, checkPwaMeta, checkPwaOffline, checkStoreLink, checkTextSelectable, checkUnsafeVh, checkViewportSupport, fsFileSource, githubTreeSource, isGameProject, mapFileSource, };
38
41
  /**
39
42
  * Runs every compliance check against the source. Two front doors:
40
43
  * - `runChecks(repoDir)` — CLI / CI; reads from disk.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAmB,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACtF,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIvE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAEvE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAE3F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { checkBrandFonts } from './checks/brand-fonts.js';
2
2
  import { checkBrandTokens } from './checks/brand-tokens.js';
3
3
  import { checkBundleSize } from './checks/bundle-size.js';
4
4
  import { checkClaudeMdSlim } from './checks/claude-md-slim.js';
5
+ import { checkCssDiscipline } from './checks/css-discipline.js';
5
6
  import { checkDarkMode } from './checks/dark-mode.js';
6
7
  import { checkHtmlMeta } from './checks/html-meta.js';
7
8
  import { checkLicenseMit } from './checks/license-mit.js';
@@ -10,10 +11,12 @@ import { checkNoAds } from './checks/no-ads.js';
10
11
  import { checkNoBrandOverrides } from './checks/no-brand-overrides.js';
11
12
  import { checkNoCommittedArtifacts } from './checks/no-committed-artifacts.js';
12
13
  import { checkNoEnvProduction } from './checks/no-env-production.js';
14
+ import { checkNoExcessiveInlineStyles } from './checks/no-excessive-inline-styles.js';
13
15
  import { checkNoPayments } from './checks/no-payments.js';
14
16
  import { checkNoPlaceholders } from './checks/no-placeholders.js';
15
17
  import { checkNoScroll } from './checks/no-scroll.js';
16
18
  import { checkNoTracking } from './checks/no-tracking.js';
19
+ import { checkOpaqueSurface } from './checks/opaque-surface.js';
17
20
  import { checkPermissions } from './checks/permissions.js';
18
21
  import { checkMaskableIcon } from './checks/pwa-maskable-icon.js';
19
22
  import { checkPwaMeta } from './checks/pwa-meta.js';
@@ -32,7 +35,7 @@ export { detectPermissions, PERMISSION_IDS, readDeclaredPermissions, } from './l
32
35
  // browser/Workers env, no filesystem). Separate export path so callers
33
36
  // don't accidentally pull node:fs in via the file-walking checks.
34
37
  export { auditLive, checkBrandFontsLive, checkBundleSizeLive, checkManifestLive, checkNoAdsLive, checkNoTrackingLive, checkUnsafeVhLive, } from './live/index.js';
35
- export { checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoAds, checkNoBrandOverrides, checkNoCommittedArtifacts, checkNoEnvProduction, checkNoPayments, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPermissions, checkPwaMeta, checkPwaOffline, checkStoreLink, checkTextSelectable, checkUnsafeVh, checkViewportSupport, fsFileSource, githubTreeSource, isGameProject, mapFileSource, };
38
+ export { checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkCssDiscipline, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoAds, checkNoBrandOverrides, checkNoCommittedArtifacts, checkNoEnvProduction, checkNoExcessiveInlineStyles, checkNoPayments, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkOpaqueSurface, checkPermissions, checkPwaMeta, checkPwaOffline, checkStoreLink, checkTextSelectable, checkUnsafeVh, checkViewportSupport, fsFileSource, githubTreeSource, isGameProject, mapFileSource, };
36
39
  /**
37
40
  * Runs every compliance check against the source. Two front doors:
38
41
  * - `runChecks(repoDir)` — CLI / CI; reads from disk.
@@ -72,6 +75,9 @@ async function runChecksOn(source) {
72
75
  checkStoreLink(source),
73
76
  checkTextSelectable(source),
74
77
  checkDarkMode(source),
78
+ checkCssDiscipline(source),
79
+ checkNoExcessiveInlineStyles(source),
80
+ checkOpaqueSurface(source),
75
81
  checkBundleSize(source),
76
82
  checkClaudeMdSlim(source),
77
83
  ]);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAmB,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE3F,OAAO,EAAE,qBAAqB,EAAuB,MAAM,0BAA0B,CAAC;AAEtF,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAE9B,+DAA+D;AAC/D,uEAAuE;AACvE,kEAAkE;AAClE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,4BAA4B,EAC5B,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe;IAC7C,OAAO,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA0B;IACjE,OAAO,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,MAAkB;IAC3C,OAAO,OAAO,CAAC,GAAG,CAAC;QACjB,eAAe,CAAC,MAAM,CAAC;QACvB,yBAAyB,CAAC,MAAM,CAAC;QACjC,oBAAoB,CAAC,MAAM,CAAC;QAC5B,mBAAmB,CAAC,MAAM,CAAC;QAC3B,eAAe,CAAC,MAAM,CAAC;QACvB,eAAe,CAAC,MAAM,CAAC;QACvB,UAAU,CAAC,MAAM,CAAC;QAClB,gBAAgB,CAAC,MAAM,CAAC;QACxB,eAAe,CAAC,MAAM,CAAC;QACvB,gBAAgB,CAAC,MAAM,CAAC;QACxB,qBAAqB,CAAC,MAAM,CAAC;QAC7B,aAAa,CAAC,MAAM,CAAC;QACrB,oBAAoB,CAAC,MAAM,CAAC;QAC5B,aAAa,CAAC,MAAM,CAAC;QACrB,aAAa,CAAC,MAAM,CAAC;QACrB,YAAY,CAAC,MAAM,CAAC;QACpB,eAAe,CAAC,MAAM,CAAC;QACvB,aAAa,CAAC,MAAM,CAAC;QACrB,iBAAiB,CAAC,MAAM,CAAC;QACzB,cAAc,CAAC,MAAM,CAAC;QACtB,mBAAmB,CAAC,MAAM,CAAC;QAC3B,aAAa,CAAC,MAAM,CAAC;QACrB,kBAAkB,CAAC,MAAM,CAAC;QAC1B,4BAA4B,CAAC,MAAM,CAAC;QACpC,kBAAkB,CAAC,MAAM,CAAC;QAC1B,eAAe,CAAC,MAAM,CAAC;QACvB,iBAAiB,CAAC,MAAM,CAAC;KAC1B,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type Node, type Root, type Rule } from 'postcss';
2
+ import type { FileSource } from './file-source.js';
3
+ export declare function isTokenRule(rule: Rule): boolean;
4
+ export declare function within(node: Node, name: string): boolean;
5
+ export declare function stylesheets(source: FileSource): AsyncGenerator<{
6
+ path: string;
7
+ root?: Root;
8
+ error?: string;
9
+ }>;
10
+ //# sourceMappingURL=styling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styling.d.ts","sourceRoot":"","sources":["../../src/lib/styling.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAI/C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxD;AAED,wBAAuB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAWD"}
@@ -0,0 +1,27 @@
1
+ import postcss, {} from 'postcss';
2
+ export function isTokenRule(rule) {
3
+ return rule.selectors.every((selector) => /^:root(?:\[data-theme\s*=\s*["']?(?:dark|light)["']?\])?$/.test(selector.trim()));
4
+ }
5
+ export function within(node, name) {
6
+ for (let parent = node.parent; parent; parent = parent.parent) {
7
+ if (parent.type === 'atrule' && 'name' in parent && parent.name === name)
8
+ return true;
9
+ }
10
+ return false;
11
+ }
12
+ export async function* stylesheets(source) {
13
+ for await (const path of source.list()) {
14
+ if (!path.startsWith('web/src/') || !path.endsWith('.css'))
15
+ continue;
16
+ const css = await source.read(path);
17
+ if (css === null)
18
+ continue;
19
+ try {
20
+ yield { path, root: postcss.parse(css, { from: path }) };
21
+ }
22
+ catch (error) {
23
+ yield { path, error: String(error) };
24
+ }
25
+ }
26
+ }
27
+ //# sourceMappingURL=styling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styling.js","sourceRoot":"","sources":["../../src/lib/styling.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAmC,MAAM,SAAS,CAAC;AAGnE,MAAM,UAAU,WAAW,CAAC,IAAU;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE,CACvC,2DAA2D,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAClF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAU,EAAE,IAAY;IAC7C,KAAK,IAAI,MAAM,GAAqB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAChF,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,WAAW,CAAC,MAAkB;IAKnD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAS;QACrE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freeappstore/compliance",
3
- "version": "0.7.19",
3
+ "version": "0.7.20",
4
4
  "description": "Compliance checks for apps published on freeappstore.online — used by the CLI for local feedback and by CI for gating.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,6 +40,9 @@
40
40
  "typescript": "^5.9.3"
41
41
  },
42
42
  "sideEffects": false,
43
+ "dependencies": {
44
+ "postcss": "^8.5.32"
45
+ },
43
46
  "scripts": {
44
47
  "build": "tsc",
45
48
  "typecheck": "tsc --noEmit"