@freeappstore/compliance 0.3.0 → 0.6.0
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/dist/checks/brand-fonts.d.ts +2 -1
- package/dist/checks/brand-fonts.d.ts.map +1 -1
- package/dist/checks/brand-fonts.js +11 -7
- package/dist/checks/brand-fonts.js.map +1 -1
- package/dist/checks/brand-tokens.d.ts +22 -0
- package/dist/checks/brand-tokens.d.ts.map +1 -0
- package/dist/checks/brand-tokens.js +53 -0
- package/dist/checks/brand-tokens.js.map +1 -0
- package/dist/checks/bundle-size.d.ts +7 -1
- package/dist/checks/bundle-size.d.ts.map +1 -1
- package/dist/checks/bundle-size.js +35 -15
- package/dist/checks/bundle-size.js.map +1 -1
- package/dist/checks/claude-md-slim.d.ts +4 -0
- package/dist/checks/claude-md-slim.d.ts.map +1 -0
- package/dist/checks/claude-md-slim.js +88 -0
- package/dist/checks/claude-md-slim.js.map +1 -0
- package/dist/checks/dark-mode.d.ts +20 -0
- package/dist/checks/dark-mode.d.ts.map +1 -0
- package/dist/checks/dark-mode.js +56 -0
- package/dist/checks/dark-mode.js.map +1 -0
- package/dist/checks/html-meta.d.ts +16 -0
- package/dist/checks/html-meta.d.ts.map +1 -0
- package/dist/checks/html-meta.js +51 -0
- package/dist/checks/html-meta.js.map +1 -0
- package/dist/checks/license-mit.d.ts +13 -0
- package/dist/checks/license-mit.d.ts.map +1 -0
- package/dist/checks/license-mit.js +45 -0
- package/dist/checks/license-mit.js.map +1 -0
- package/dist/checks/manifest.d.ts +2 -1
- package/dist/checks/manifest.d.ts.map +1 -1
- package/dist/checks/manifest.js +7 -12
- package/dist/checks/manifest.js.map +1 -1
- package/dist/checks/no-brand-overrides.d.ts +2 -1
- package/dist/checks/no-brand-overrides.d.ts.map +1 -1
- package/dist/checks/no-brand-overrides.js +94 -30
- package/dist/checks/no-brand-overrides.js.map +1 -1
- package/dist/checks/no-env-production.d.ts +16 -0
- package/dist/checks/no-env-production.d.ts.map +1 -0
- package/dist/checks/no-env-production.js +37 -0
- package/dist/checks/no-env-production.js.map +1 -0
- package/dist/checks/no-placeholders.d.ts +2 -1
- package/dist/checks/no-placeholders.d.ts.map +1 -1
- package/dist/checks/no-placeholders.js +11 -9
- package/dist/checks/no-placeholders.js.map +1 -1
- package/dist/checks/no-scroll.d.ts +2 -1
- package/dist/checks/no-scroll.d.ts.map +1 -1
- package/dist/checks/no-scroll.js +13 -47
- package/dist/checks/no-scroll.js.map +1 -1
- package/dist/checks/no-tracking.d.ts +2 -1
- package/dist/checks/no-tracking.d.ts.map +1 -1
- package/dist/checks/no-tracking.js +77 -21
- package/dist/checks/no-tracking.js.map +1 -1
- package/dist/checks/pwa-meta.d.ts +19 -0
- package/dist/checks/pwa-meta.d.ts.map +1 -0
- package/dist/checks/pwa-meta.js +42 -0
- package/dist/checks/pwa-meta.js.map +1 -0
- package/dist/checks/pwa-offline.d.ts +40 -0
- package/dist/checks/pwa-offline.d.ts.map +1 -0
- package/dist/checks/pwa-offline.js +388 -0
- package/dist/checks/pwa-offline.js.map +1 -0
- package/dist/checks/store-link.d.ts +17 -0
- package/dist/checks/store-link.d.ts.map +1 -0
- package/dist/checks/store-link.js +36 -0
- package/dist/checks/store-link.js.map +1 -0
- package/dist/checks/unsafe-vh.d.ts +2 -1
- package/dist/checks/unsafe-vh.d.ts.map +1 -1
- package/dist/checks/unsafe-vh.js +25 -15
- package/dist/checks/unsafe-vh.js.map +1 -1
- package/dist/checks/viewport-support.d.ts +2 -1
- package/dist/checks/viewport-support.d.ts.map +1 -1
- package/dist/checks/viewport-support.js +13 -8
- package/dist/checks/viewport-support.js.map +1 -1
- package/dist/index.d.ts +28 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/file-source.d.ts +52 -0
- package/dist/lib/file-source.d.ts.map +1 -0
- package/dist/lib/file-source.js +156 -0
- package/dist/lib/file-source.js.map +1 -0
- package/dist/lib/gzip.d.ts +8 -0
- package/dist/lib/gzip.d.ts.map +1 -0
- package/dist/lib/gzip.js +26 -0
- package/dist/lib/gzip.js.map +1 -0
- package/dist/lib/project-type.d.ts +18 -0
- package/dist/lib/project-type.d.ts.map +1 -0
- package/dist/lib/project-type.js +34 -0
- package/dist/lib/project-type.js.map +1 -0
- package/dist/lib/strip.d.ts +60 -0
- package/dist/lib/strip.d.ts.map +1 -0
- package/dist/lib/strip.js +169 -0
- package/dist/lib/strip.js.map +1 -0
- package/dist/live/index.d.ts.map +1 -1
- package/dist/live/index.js +14 -8
- package/dist/live/index.js.map +1 -1
- package/package.json +10 -10
- package/LICENSE +0 -21
- package/dist/checks/brand-fonts.test.d.ts +0 -2
- package/dist/checks/brand-fonts.test.d.ts.map +0 -1
- package/dist/checks/brand-fonts.test.js +0 -45
- package/dist/checks/brand-fonts.test.js.map +0 -1
- package/dist/checks/bundle-size.test.d.ts +0 -2
- package/dist/checks/bundle-size.test.d.ts.map +0 -1
- package/dist/checks/bundle-size.test.js +0 -57
- package/dist/checks/bundle-size.test.js.map +0 -1
- package/dist/checks/manifest.test.d.ts +0 -2
- package/dist/checks/manifest.test.d.ts.map +0 -1
- package/dist/checks/manifest.test.js +0 -53
- package/dist/checks/manifest.test.js.map +0 -1
- package/dist/checks/no-brand-overrides.test.d.ts +0 -2
- package/dist/checks/no-brand-overrides.test.d.ts.map +0 -1
- package/dist/checks/no-brand-overrides.test.js +0 -102
- package/dist/checks/no-brand-overrides.test.js.map +0 -1
- package/dist/checks/no-placeholders.test.d.ts +0 -2
- package/dist/checks/no-placeholders.test.d.ts.map +0 -1
- package/dist/checks/no-placeholders.test.js +0 -46
- package/dist/checks/no-placeholders.test.js.map +0 -1
- package/dist/checks/no-scroll.test.d.ts +0 -2
- package/dist/checks/no-scroll.test.d.ts.map +0 -1
- package/dist/checks/no-scroll.test.js +0 -105
- package/dist/checks/no-scroll.test.js.map +0 -1
- package/dist/checks/no-tracking.test.d.ts +0 -2
- package/dist/checks/no-tracking.test.d.ts.map +0 -1
- package/dist/checks/no-tracking.test.js +0 -42
- package/dist/checks/no-tracking.test.js.map +0 -1
- package/dist/checks/unsafe-vh.test.d.ts +0 -2
- package/dist/checks/unsafe-vh.test.d.ts.map +0 -1
- package/dist/checks/unsafe-vh.test.js +0 -115
- package/dist/checks/unsafe-vh.test.js.map +0 -1
- package/dist/checks/viewport-support.test.d.ts +0 -2
- package/dist/checks/viewport-support.test.d.ts.map +0 -1
- package/dist/checks/viewport-support.test.js +0 -63
- package/dist/checks/viewport-support.test.js.map +0 -1
- package/dist/lib/walk.d.ts +0 -6
- package/dist/lib/walk.d.ts.map +0 -1
- package/dist/lib/walk.js +0 -35
- package/dist/lib/walk.js.map +0 -1
- package/dist/live/index.test.d.ts +0 -2
- package/dist/live/index.test.d.ts.map +0 -1
- package/dist/live/index.test.js +0 -259
- package/dist/live/index.test.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freeappstore/compliance",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://github.com/freeappstore-online/
|
|
15
|
+
"homepage": "https://github.com/freeappstore-online/platform#readme",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/freeappstore-online/
|
|
18
|
+
"url": "git+https://github.com/freeappstore-online/platform.git",
|
|
19
19
|
"directory": "packages/compliance"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/freeappstore-online/
|
|
22
|
+
"url": "https://github.com/freeappstore-online/platform/issues"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"freeappstore",
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=22"
|
|
37
37
|
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
41
|
+
},
|
|
38
42
|
"devDependencies": {
|
|
39
43
|
"@types/node": "^22.0.0",
|
|
40
44
|
"typescript": "^5.7.0"
|
|
41
45
|
},
|
|
42
|
-
"sideEffects": false
|
|
43
|
-
|
|
44
|
-
"build": "tsc",
|
|
45
|
-
"typecheck": "tsc --noEmit"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
46
|
+
"sideEffects": false
|
|
47
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 FreeAppStore
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"brand-fonts.test.d.ts","sourceRoot":"","sources":["../../src/checks/brand-fonts.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkBrandFonts } from './brand-fonts.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
dir = await mkdtemp(join(tmpdir(), 'fas-compliance-'));
|
|
9
|
-
await mkdir(join(dir, 'web', 'src'), { recursive: true });
|
|
10
|
-
});
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
await rm(dir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
describe('checkBrandFonts', () => {
|
|
15
|
-
it('passes when both Manrope and Fraunces are referenced', async () => {
|
|
16
|
-
await writeFile(join(dir, 'web', 'src', 'index.css'), 'body { font-family: Manrope, sans-serif; } h1 { font-family: Fraunces; }');
|
|
17
|
-
const r = await checkBrandFonts(dir);
|
|
18
|
-
expect(r.status).toBe('pass');
|
|
19
|
-
});
|
|
20
|
-
it('passes with fonts split across files', async () => {
|
|
21
|
-
await writeFile(join(dir, 'web', 'src', 'a.css'), '@import "Manrope";');
|
|
22
|
-
await writeFile(join(dir, 'web', 'src', 'b.css'), '@import "Fraunces";');
|
|
23
|
-
const r = await checkBrandFonts(dir);
|
|
24
|
-
expect(r.status).toBe('pass');
|
|
25
|
-
});
|
|
26
|
-
it('passes when fonts are in HTML link tag (Google Fonts)', async () => {
|
|
27
|
-
await writeFile(join(dir, 'web', 'index.html'), '<link href="https://fonts.googleapis.com/css2?family=Manrope&family=Fraunces" rel="stylesheet">');
|
|
28
|
-
const r = await checkBrandFonts(dir);
|
|
29
|
-
expect(r.status).toBe('pass');
|
|
30
|
-
});
|
|
31
|
-
it('fails when only one of the two is present', async () => {
|
|
32
|
-
await writeFile(join(dir, 'web', 'src', 'a.css'), '@import "Manrope";');
|
|
33
|
-
const r = await checkBrandFonts(dir);
|
|
34
|
-
expect(r.status).toBe('fail');
|
|
35
|
-
expect(r.detail).toMatch(/Fraunces/);
|
|
36
|
-
});
|
|
37
|
-
it('fails when neither is present', async () => {
|
|
38
|
-
await writeFile(join(dir, 'web', 'src', 'a.css'), 'body { font: Helvetica; }');
|
|
39
|
-
const r = await checkBrandFonts(dir);
|
|
40
|
-
expect(r.status).toBe('fail');
|
|
41
|
-
expect(r.detail).toMatch(/Manrope/);
|
|
42
|
-
expect(r.detail).toMatch(/Fraunces/);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
//# sourceMappingURL=brand-fonts.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"brand-fonts.test.js","sourceRoot":"","sources":["../../src/checks/brand-fonts.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundle-size.test.d.ts","sourceRoot":"","sources":["../../src/checks/bundle-size.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkBundleSize } from './bundle-size.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
dir = await mkdtemp(join(tmpdir(), 'fas-compliance-'));
|
|
9
|
-
});
|
|
10
|
-
afterEach(async () => {
|
|
11
|
-
await rm(dir, { recursive: true, force: true });
|
|
12
|
-
});
|
|
13
|
-
async function writeAsset(name, content) {
|
|
14
|
-
const p = join(dir, 'web', 'dist', 'assets');
|
|
15
|
-
await mkdir(p, { recursive: true });
|
|
16
|
-
await writeFile(join(p, name), content);
|
|
17
|
-
}
|
|
18
|
-
describe('checkBundleSize', () => {
|
|
19
|
-
it('warns when web/dist not built', async () => {
|
|
20
|
-
const r = await checkBundleSize(dir);
|
|
21
|
-
expect(r.status).toBe('warn');
|
|
22
|
-
expect(r.detail).toMatch(/pnpm build/);
|
|
23
|
-
});
|
|
24
|
-
it('warns when no JS files in assets', async () => {
|
|
25
|
-
const p = join(dir, 'web', 'dist', 'assets');
|
|
26
|
-
await mkdir(p, { recursive: true });
|
|
27
|
-
await writeFile(join(p, 'styles.css'), 'body{color:red}');
|
|
28
|
-
const r = await checkBundleSize(dir);
|
|
29
|
-
expect(r.status).toBe('warn');
|
|
30
|
-
expect(r.detail).toMatch(/no JS/);
|
|
31
|
-
});
|
|
32
|
-
it('passes when largest JS is under 300KB gzipped', async () => {
|
|
33
|
-
// ~100KB of repetitive content gzips to a few KB
|
|
34
|
-
await writeAsset('index-abc.js', 'a'.repeat(100_000));
|
|
35
|
-
const r = await checkBundleSize(dir);
|
|
36
|
-
expect(r.status).toBe('pass');
|
|
37
|
-
expect(r.detail).toMatch(/index-abc\.js/);
|
|
38
|
-
expect(r.detail).toMatch(/limit 300 KB/);
|
|
39
|
-
});
|
|
40
|
-
it('picks the largest JS file for measurement', async () => {
|
|
41
|
-
await writeAsset('small.js', 'tiny');
|
|
42
|
-
await writeAsset('big.js', 'a'.repeat(200_000));
|
|
43
|
-
const r = await checkBundleSize(dir);
|
|
44
|
-
expect(r.detail).toMatch(/big\.js/);
|
|
45
|
-
});
|
|
46
|
-
it('fails when largest JS exceeds 300KB gzipped', async () => {
|
|
47
|
-
// Random bytes don't compress, so 400KB of randomness ~= 400KB gzipped.
|
|
48
|
-
const random = Buffer.alloc(400 * 1024);
|
|
49
|
-
for (let i = 0; i < random.length; i++)
|
|
50
|
-
random[i] = Math.floor(Math.random() * 256);
|
|
51
|
-
await writeAsset('huge.js', random);
|
|
52
|
-
const r = await checkBundleSize(dir);
|
|
53
|
-
expect(r.status).toBe('fail');
|
|
54
|
-
expect(r.suggestions?.length ?? 0).toBeGreaterThan(0);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
//# sourceMappingURL=bundle-size.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bundle-size.test.js","sourceRoot":"","sources":["../../src/checks/bundle-size.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.test.d.ts","sourceRoot":"","sources":["../../src/checks/manifest.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkManifest } from './manifest.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
dir = await mkdtemp(join(tmpdir(), 'fas-compliance-'));
|
|
9
|
-
});
|
|
10
|
-
afterEach(async () => {
|
|
11
|
-
await rm(dir, { recursive: true, force: true });
|
|
12
|
-
});
|
|
13
|
-
async function withManifest(content) {
|
|
14
|
-
await mkdir(join(dir, 'web', 'public'), { recursive: true });
|
|
15
|
-
await writeFile(join(dir, 'web', 'public', 'manifest.json'), content);
|
|
16
|
-
}
|
|
17
|
-
describe('checkManifest', () => {
|
|
18
|
-
it('fails when manifest.json missing', async () => {
|
|
19
|
-
const r = await checkManifest(dir);
|
|
20
|
-
expect(r.status).toBe('fail');
|
|
21
|
-
expect(r.detail).toMatch(/missing/);
|
|
22
|
-
});
|
|
23
|
-
it('fails when manifest.json is not valid JSON', async () => {
|
|
24
|
-
await withManifest('{ not json');
|
|
25
|
-
const r = await checkManifest(dir);
|
|
26
|
-
expect(r.status).toBe('fail');
|
|
27
|
-
expect(r.detail).toMatch(/JSON/i);
|
|
28
|
-
});
|
|
29
|
-
it('warns when required fields are missing', async () => {
|
|
30
|
-
await withManifest(JSON.stringify({ name: 'My App' }));
|
|
31
|
-
const r = await checkManifest(dir);
|
|
32
|
-
expect(r.status).toBe('warn');
|
|
33
|
-
expect(r.detail).toMatch(/short_name/);
|
|
34
|
-
expect(r.detail).toMatch(/start_url/);
|
|
35
|
-
});
|
|
36
|
-
it('passes with all four required fields present', async () => {
|
|
37
|
-
await withManifest(JSON.stringify({
|
|
38
|
-
name: 'My App',
|
|
39
|
-
short_name: 'MyApp',
|
|
40
|
-
start_url: '/',
|
|
41
|
-
display: 'standalone',
|
|
42
|
-
}));
|
|
43
|
-
const r = await checkManifest(dir);
|
|
44
|
-
expect(r.status).toBe('pass');
|
|
45
|
-
});
|
|
46
|
-
it('treats empty-string values for required fields as missing', async () => {
|
|
47
|
-
await withManifest(JSON.stringify({ name: '', short_name: 'X', start_url: '/', display: 'standalone' }));
|
|
48
|
-
const r = await checkManifest(dir);
|
|
49
|
-
expect(r.status).toBe('warn');
|
|
50
|
-
expect(r.detail).toMatch(/name/);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=manifest.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.test.js","sourceRoot":"","sources":["../../src/checks/manifest.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-brand-overrides.test.d.ts","sourceRoot":"","sources":["../../src/checks/no-brand-overrides.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkNoBrandOverrides, scanContent } from './no-brand-overrides.js';
|
|
6
|
-
async function fixture(files) {
|
|
7
|
-
const dir = await mkdtemp(join(tmpdir(), 'fas-brand-'));
|
|
8
|
-
for (const [path, content] of Object.entries(files)) {
|
|
9
|
-
const full = join(dir, path);
|
|
10
|
-
await mkdir(join(full, '..'), { recursive: true });
|
|
11
|
-
await writeFile(full, content);
|
|
12
|
-
}
|
|
13
|
-
return dir;
|
|
14
|
-
}
|
|
15
|
-
describe('scanContent (unit)', () => {
|
|
16
|
-
it('flags an override of a protected CSS variable', () => {
|
|
17
|
-
const issues = scanContent('web/src/index.css', `
|
|
18
|
-
:root { --accent: hotpink; }
|
|
19
|
-
`);
|
|
20
|
-
expect(issues).toHaveLength(1);
|
|
21
|
-
expect(issues[0]).toMatch(/--accent/);
|
|
22
|
-
});
|
|
23
|
-
it('does NOT flag using the variable via var()', () => {
|
|
24
|
-
const issues = scanContent('web/src/App.tsx', `
|
|
25
|
-
<div style={{ color: 'var(--accent)' }} />
|
|
26
|
-
`);
|
|
27
|
-
expect(issues).toEqual([]);
|
|
28
|
-
});
|
|
29
|
-
it('does not flag a non-protected custom variable (apps can have their own)', () => {
|
|
30
|
-
const issues = scanContent('web/src/index.css', `
|
|
31
|
-
:root { --my-shadow: 0 0 4px black; }
|
|
32
|
-
`);
|
|
33
|
-
expect(issues).toEqual([]);
|
|
34
|
-
});
|
|
35
|
-
it('flags a non-brand font-family in CSS', () => {
|
|
36
|
-
const issues = scanContent('web/src/index.css', `
|
|
37
|
-
h1 { font-family: "Cormorant Garamond", serif; }
|
|
38
|
-
`);
|
|
39
|
-
expect(issues).toHaveLength(1);
|
|
40
|
-
expect(issues[0]).toMatch(/cormorant garamond/);
|
|
41
|
-
});
|
|
42
|
-
it('flags a non-brand font in inline JSX styles', () => {
|
|
43
|
-
const issues = scanContent('web/src/App.tsx', `
|
|
44
|
-
<h1 style={{ fontFamily: "Sora, sans-serif" }} />
|
|
45
|
-
`);
|
|
46
|
-
expect(issues).toHaveLength(1);
|
|
47
|
-
expect(issues[0]).toMatch(/sora/);
|
|
48
|
-
});
|
|
49
|
-
it('accepts brand fonts and system fallbacks', () => {
|
|
50
|
-
const issues = scanContent('web/src/index.css', `
|
|
51
|
-
body { font-family: "Manrope", system-ui, sans-serif; }
|
|
52
|
-
h1 { font-family: Fraunces, Georgia, serif; }
|
|
53
|
-
code { font-family: "SF Mono", Menlo, monospace; }
|
|
54
|
-
`);
|
|
55
|
-
expect(issues).toEqual([]);
|
|
56
|
-
});
|
|
57
|
-
it('reports line numbers', () => {
|
|
58
|
-
const issues = scanContent('web/src/index.css', `\n\n:root { --paper: red; }\n`);
|
|
59
|
-
expect(issues[0]).toMatch(/:3 /);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
describe('checkNoBrandOverrides (integration)', () => {
|
|
63
|
-
it('passes when all CSS uses brand tokens', async () => {
|
|
64
|
-
const dir = await fixture({
|
|
65
|
-
'web/src/index.css': `
|
|
66
|
-
:root { --my-extra: 4px; }
|
|
67
|
-
body { font-family: Manrope, system-ui, sans-serif; }
|
|
68
|
-
h1 { font-family: Fraunces, serif; color: var(--accent); }
|
|
69
|
-
`,
|
|
70
|
-
});
|
|
71
|
-
const r = await checkNoBrandOverrides(dir);
|
|
72
|
-
expect(r.status).toBe('pass');
|
|
73
|
-
});
|
|
74
|
-
it('fails when an app overrides a protected variable in a non-theme CSS file', async () => {
|
|
75
|
-
// web/src/index.css is the canonical theme file (exempt). Per-component
|
|
76
|
-
// CSS like this isn't.
|
|
77
|
-
const dir = await fixture({
|
|
78
|
-
'web/src/components/Branding.css': `:root { --accent: deeppink; }`,
|
|
79
|
-
});
|
|
80
|
-
const r = await checkNoBrandOverrides(dir);
|
|
81
|
-
expect(r.status).toBe('fail');
|
|
82
|
-
expect(r.detail).toMatch(/override/);
|
|
83
|
-
expect(r.suggestions?.join(' ')).toMatch(/var\(--accent\)/);
|
|
84
|
-
});
|
|
85
|
-
it('does NOT fail when web/src/index.css legitimately defines tokens (template-owned)', async () => {
|
|
86
|
-
const dir = await fixture({
|
|
87
|
-
'web/src/index.css': `:root { --paper: #ffffff; --ink: #1a1a1a; --accent: #2563eb; }`,
|
|
88
|
-
});
|
|
89
|
-
const r = await checkNoBrandOverrides(dir);
|
|
90
|
-
expect(r.status).toBe('pass');
|
|
91
|
-
});
|
|
92
|
-
it('fails when an app uses non-brand fonts', async () => {
|
|
93
|
-
const dir = await fixture({
|
|
94
|
-
'web/src/App.tsx': `
|
|
95
|
-
const h1 = <h1 style={{ fontFamily: "Cormorant Garamond, serif" }} />;
|
|
96
|
-
`,
|
|
97
|
-
});
|
|
98
|
-
const r = await checkNoBrandOverrides(dir);
|
|
99
|
-
expect(r.status).toBe('fail');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
//# sourceMappingURL=no-brand-overrides.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-brand-overrides.test.js","sourceRoot":"","sources":["../../src/checks/no-brand-overrides.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-placeholders.test.d.ts","sourceRoot":"","sources":["../../src/checks/no-placeholders.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkNoPlaceholders } from './no-placeholders.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
dir = await mkdtemp(join(tmpdir(), 'fas-compliance-'));
|
|
9
|
-
});
|
|
10
|
-
afterEach(async () => {
|
|
11
|
-
await rm(dir, { recursive: true, force: true });
|
|
12
|
-
});
|
|
13
|
-
describe('checkNoPlaceholders', () => {
|
|
14
|
-
it('passes when no APPNAME anywhere', async () => {
|
|
15
|
-
await writeFile(join(dir, 'README.md'), '# my-app\nNo placeholders here.');
|
|
16
|
-
await writeFile(join(dir, 'package.json'), '{"name":"my-app"}');
|
|
17
|
-
const r = await checkNoPlaceholders(dir);
|
|
18
|
-
expect(r.status).toBe('pass');
|
|
19
|
-
});
|
|
20
|
-
it('fails with file list when APPNAME is left in any text file', async () => {
|
|
21
|
-
await writeFile(join(dir, 'README.md'), '# APPNAME\n');
|
|
22
|
-
await mkdir(join(dir, 'web'));
|
|
23
|
-
await writeFile(join(dir, 'web', 'index.html'), '<title>APPNAME — FreeAppStore</title>');
|
|
24
|
-
const r = await checkNoPlaceholders(dir);
|
|
25
|
-
expect(r.status).toBe('fail');
|
|
26
|
-
expect(r.detail).toMatch(/README\.md/);
|
|
27
|
-
expect(r.detail).toMatch(/index\.html/);
|
|
28
|
-
expect(r.suggestions?.length ?? 0).toBeGreaterThan(0);
|
|
29
|
-
});
|
|
30
|
-
it('skips binary-ish extensions (no false positives on icons etc.)', async () => {
|
|
31
|
-
// .png file with bytes that happen to spell APPNAME — should be skipped
|
|
32
|
-
await writeFile(join(dir, 'icon.png'), Buffer.from('APPNAME'));
|
|
33
|
-
const r = await checkNoPlaceholders(dir);
|
|
34
|
-
expect(r.status).toBe('pass');
|
|
35
|
-
});
|
|
36
|
-
it('caps at 5 reported files when many offend', async () => {
|
|
37
|
-
await mkdir(join(dir, 'web'));
|
|
38
|
-
for (let i = 0; i < 10; i++) {
|
|
39
|
-
await writeFile(join(dir, 'web', `file${i}.ts`), 'const x = "APPNAME";');
|
|
40
|
-
}
|
|
41
|
-
const r = await checkNoPlaceholders(dir);
|
|
42
|
-
expect(r.status).toBe('fail');
|
|
43
|
-
expect(r.detail).toMatch(/5\+/);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
//# sourceMappingURL=no-placeholders.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-placeholders.test.js","sourceRoot":"","sources":["../../src/checks/no-placeholders.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-scroll.test.d.ts","sourceRoot":"","sources":["../../src/checks/no-scroll.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkNoScroll } from './no-scroll.js';
|
|
6
|
-
async function fixture(files) {
|
|
7
|
-
const dir = await mkdtemp(join(tmpdir(), 'fas-noscroll-'));
|
|
8
|
-
for (const [path, content] of Object.entries(files)) {
|
|
9
|
-
const full = join(dir, path);
|
|
10
|
-
await mkdir(join(full, '..'), { recursive: true });
|
|
11
|
-
await writeFile(full, content);
|
|
12
|
-
}
|
|
13
|
-
return dir;
|
|
14
|
-
}
|
|
15
|
-
const GAME_DEPS = JSON.stringify({
|
|
16
|
-
name: 'my-game',
|
|
17
|
-
dependencies: { '@freeappstore/games': '^0.1.0' },
|
|
18
|
-
});
|
|
19
|
-
describe('checkNoScroll', () => {
|
|
20
|
-
it('passes (skipped) when the project is not a game', async () => {
|
|
21
|
-
const dir = await fixture({
|
|
22
|
-
'package.json': JSON.stringify({ name: 'my-app' }),
|
|
23
|
-
'web/src/index.css': 'body { overflow: scroll; }',
|
|
24
|
-
});
|
|
25
|
-
const r = await checkNoScroll(dir);
|
|
26
|
-
expect(r.status).toBe('pass');
|
|
27
|
-
expect(r.detail).toMatch(/not a game/);
|
|
28
|
-
});
|
|
29
|
-
it('detects @freeappstore/games dep as the game signal', async () => {
|
|
30
|
-
const dir = await fixture({
|
|
31
|
-
'package.json': GAME_DEPS,
|
|
32
|
-
'web/src/index.css': 'body { height: 100svh; }',
|
|
33
|
-
'web/src/App.tsx': 'import { GameShell } from "@freeappstore/games";',
|
|
34
|
-
});
|
|
35
|
-
const r = await checkNoScroll(dir);
|
|
36
|
-
// Should at least run the check, not skip.
|
|
37
|
-
expect(r.detail).not.toMatch(/not a game/);
|
|
38
|
-
});
|
|
39
|
-
it('fails when html/body declares overflow: scroll', async () => {
|
|
40
|
-
const dir = await fixture({
|
|
41
|
-
'package.json': GAME_DEPS,
|
|
42
|
-
'web/src/index.css': 'html { overflow: scroll; }',
|
|
43
|
-
});
|
|
44
|
-
const r = await checkNoScroll(dir);
|
|
45
|
-
expect(r.status).toBe('fail');
|
|
46
|
-
expect(r.suggestions?.join(' ')).toMatch(/GameShell/);
|
|
47
|
-
});
|
|
48
|
-
it('fails when html/body declares overflow: auto', async () => {
|
|
49
|
-
const dir = await fixture({
|
|
50
|
-
'package.json': GAME_DEPS,
|
|
51
|
-
'web/src/index.css': 'body { overflow: auto; }',
|
|
52
|
-
});
|
|
53
|
-
const r = await checkNoScroll(dir);
|
|
54
|
-
expect(r.status).toBe('fail');
|
|
55
|
-
});
|
|
56
|
-
it('fails on overflow-y: scroll on body', async () => {
|
|
57
|
-
const dir = await fixture({
|
|
58
|
-
'package.json': GAME_DEPS,
|
|
59
|
-
'web/src/index.css': 'body { overflow-y: scroll; padding: 0; }',
|
|
60
|
-
});
|
|
61
|
-
const r = await checkNoScroll(dir);
|
|
62
|
-
expect(r.status).toBe('fail');
|
|
63
|
-
});
|
|
64
|
-
it('fails on min-height: 100vh on body (creates page taller than viewport)', async () => {
|
|
65
|
-
const dir = await fixture({
|
|
66
|
-
'package.json': GAME_DEPS,
|
|
67
|
-
'web/src/index.css': 'body { min-height: 100vh; }',
|
|
68
|
-
});
|
|
69
|
-
const r = await checkNoScroll(dir);
|
|
70
|
-
expect(r.status).toBe('fail');
|
|
71
|
-
expect(r.suggestions?.join(' ')).toMatch(/100svh/);
|
|
72
|
-
});
|
|
73
|
-
it('warns when there is no viewport-lock evidence', async () => {
|
|
74
|
-
const dir = await fixture({
|
|
75
|
-
'package.json': GAME_DEPS,
|
|
76
|
-
'web/src/index.css': 'body { padding: 0; }',
|
|
77
|
-
'web/src/App.tsx': 'export default function App() { return <div>game</div>; }',
|
|
78
|
-
});
|
|
79
|
-
const r = await checkNoScroll(dir);
|
|
80
|
-
expect(r.status).toBe('warn');
|
|
81
|
-
expect(r.detail).toMatch(/viewport lock/);
|
|
82
|
-
});
|
|
83
|
-
it('passes when GameShell is imported (the canonical viewport lock)', async () => {
|
|
84
|
-
const dir = await fixture({
|
|
85
|
-
'package.json': GAME_DEPS,
|
|
86
|
-
'web/src/App.tsx': `
|
|
87
|
-
import { GameShell, GameTopbar } from "@freeappstore/games";
|
|
88
|
-
export default function App() {
|
|
89
|
-
return <GameShell topbar={<GameTopbar score={0} />}>game</GameShell>;
|
|
90
|
-
}
|
|
91
|
-
`,
|
|
92
|
-
});
|
|
93
|
-
const r = await checkNoScroll(dir);
|
|
94
|
-
expect(r.status).toBe('pass');
|
|
95
|
-
});
|
|
96
|
-
it('passes when CSS has explicit 100svh height lock', async () => {
|
|
97
|
-
const dir = await fixture({
|
|
98
|
-
'package.json': GAME_DEPS,
|
|
99
|
-
'web/src/index.css': '.game-root { height: 100svh; overflow: hidden; }',
|
|
100
|
-
});
|
|
101
|
-
const r = await checkNoScroll(dir);
|
|
102
|
-
expect(r.status).toBe('pass');
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
//# sourceMappingURL=no-scroll.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-scroll.test.js","sourceRoot":"","sources":["../../src/checks/no-scroll.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,KAAK,UAAU,OAAO,CAAC,KAA6B;IAClD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IAC3D,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAC/B,IAAI,EAAE,SAAS;IACf,YAAY,EAAE,EAAE,qBAAqB,EAAE,QAAQ,EAAE;CAClD,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAClD,mBAAmB,EAAE,4BAA4B;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,0BAA0B;YAC/C,iBAAiB,EAAE,kDAAkD;SACtE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,2CAA2C;QAC3C,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,4BAA4B;SAClD,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,0BAA0B;SAChD,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,0CAA0C;SAChE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,6BAA6B;SACnD,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,sBAAsB;YAC3C,iBAAiB,EAAE,2DAA2D;SAC/E,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,iBAAiB,EAAE;;;;;OAKlB;SACF,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,cAAc,EAAE,SAAS;YACzB,mBAAmB,EAAE,kDAAkD;SACxE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-tracking.test.d.ts","sourceRoot":"","sources":["../../src/checks/no-tracking.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { checkNoTracking } from './no-tracking.js';
|
|
6
|
-
let dir;
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
dir = await mkdtemp(join(tmpdir(), 'fas-compliance-'));
|
|
9
|
-
await mkdir(join(dir, 'web'));
|
|
10
|
-
});
|
|
11
|
-
afterEach(async () => {
|
|
12
|
-
await rm(dir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
describe('checkNoTracking', () => {
|
|
15
|
-
it('passes when no tracking strings anywhere', async () => {
|
|
16
|
-
await writeFile(join(dir, 'web', 'app.ts'), 'export const x = 1;');
|
|
17
|
-
const r = await checkNoTracking(dir);
|
|
18
|
-
expect(r.status).toBe('pass');
|
|
19
|
-
});
|
|
20
|
-
it('fails on google-analytics in source', async () => {
|
|
21
|
-
await writeFile(join(dir, 'web', 'index.html'), '<script src="https://www.google-analytics.com/analytics.js"></script>');
|
|
22
|
-
const r = await checkNoTracking(dir);
|
|
23
|
-
expect(r.status).toBe('fail');
|
|
24
|
-
expect(r.detail).toMatch(/google-analytics/);
|
|
25
|
-
});
|
|
26
|
-
it('fails on plausible / posthog as deps even though those are privacy-respecting', async () => {
|
|
27
|
-
// FreeAppStore policy is *no* analytics, even the privacy-respecting ones.
|
|
28
|
-
await writeFile(join(dir, 'web', 'package.json'), '{"dependencies":{"posthog-js":"1.0.0"}}');
|
|
29
|
-
const r = await checkNoTracking(dir);
|
|
30
|
-
expect(r.status).toBe('fail');
|
|
31
|
-
expect(r.detail).toMatch(/posthog/);
|
|
32
|
-
});
|
|
33
|
-
it('does not scan dist or node_modules (skipped by walk)', async () => {
|
|
34
|
-
await mkdir(join(dir, 'node_modules', 'posthog-js'), { recursive: true });
|
|
35
|
-
await writeFile(join(dir, 'node_modules', 'posthog-js', 'index.js'), '// posthog stuff');
|
|
36
|
-
await mkdir(join(dir, 'dist'));
|
|
37
|
-
await writeFile(join(dir, 'dist', 'bundle.js'), 'amplitude.track("x")');
|
|
38
|
-
const r = await checkNoTracking(dir);
|
|
39
|
-
expect(r.status).toBe('pass');
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
//# sourceMappingURL=no-tracking.test.js.map
|