mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 06:00:33 +02:00
Don't launch from the hero's Install, and check page names with V8
From the independent review of this PR: - After installing the featured app, the hero's Install on the Frame took the installed branch and launched it on the headset. It now opens the details, whose button says Open in Steam, without acting. - The duplicate-name test matched declarations at column zero only, so an indented second loadPanels (the bug it was written for) passed, and so did classes, destructuring and later declarators. It now compiles both inline scripts as one strict-mode block, where V8 rejects any name declared twice in the shared scope, with fixtures for each case and for same-named helpers in different functions (which are fine). - A card's "Won't run" overstated the check's "Might not work"; it now says May not run. - Removed styles and the source-filter state that nothing used any more. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
04995c066f
commit
497b5d9ae6
2 files changed
+45
-16
No files matched your search
@@ -1,21 +1,50 @@
|
||||
"""The page's inline scripts share one global scope, so a second top-level function or
|
||||
variable with a name already used replaces the first everywhere, silently."""
|
||||
import collections
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import unittest
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
# Compiles the scripts as one strict-mode block. There, functions are block scoped like let
|
||||
# and const, so V8 itself rejects a name declared twice in the shared scope (however it's
|
||||
# indented or declared: function, class, let, const, destructuring), while helpers with the
|
||||
# same name inside different functions stay legal.
|
||||
CHECK = r'''
|
||||
const vm = require('vm');
|
||||
const scripts = JSON.parse(require('fs').readFileSync(0, 'utf8'));
|
||||
try { new vm.Script('"use strict"; {\n' + scripts.join('\n;\n') + '\n}'); console.log('ok'); }
|
||||
catch (e) { console.log(e.message); }
|
||||
'''
|
||||
|
||||
|
||||
def check(scripts):
|
||||
r = subprocess.run(['node', '-e', CHECK], input=json.dumps(scripts), capture_output=True, text=True)
|
||||
return r.stdout.strip() or r.stderr.strip()
|
||||
|
||||
|
||||
@unittest.skipUnless(shutil.which('node'), 'Node parses the page scripts')
|
||||
class PageScripts(unittest.TestCase):
|
||||
def test_no_top_level_name_is_declared_twice(self):
|
||||
page = (ROOT / 'ui/index.html').read_text(encoding='utf-8')
|
||||
names = collections.Counter()
|
||||
for js in re.findall(r'<script>(.*?)</script>', page, re.S):
|
||||
for m in re.finditer(r'^(?:async\s+)?function\s+(\w+)|^(?:const|let|var)\s+(\w+)\s*=', js, re.M):
|
||||
names[m.group(1) or m.group(2)] += 1
|
||||
self.assertEqual({k: n for k, n in names.items() if n > 1}, {})
|
||||
self.assertEqual(check(re.findall(r'<script>(.*?)</script>', page, re.S)), 'ok')
|
||||
|
||||
def test_the_check_finds_what_it_should(self):
|
||||
twice = {
|
||||
'indented function': ['function loadPanels() {}', ' async function loadPanels() {}'],
|
||||
'class': ['class Panel {}', 'class Panel {}'],
|
||||
'destructured': ['const { a, b } = {};', 'let [b] = [];'],
|
||||
'later declarator': ['let x = 1;', 'const y = 2, x = 3;'],
|
||||
'function and const': ['function f() {}', 'const f = 1;'],
|
||||
}
|
||||
for what, scripts in twice.items():
|
||||
with self.subTest(what):
|
||||
self.assertIn('already been declared', check(scripts))
|
||||
helpers = ['function a() { function help() {} }', 'function b() { const help = 1; }']
|
||||
self.assertEqual(check(helpers), 'ok')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in new issue
Block a user