refactor: enforce noctalia.getConfig across community plugins
This commit is contained in:
@@ -65,5 +65,43 @@ class AllowedTagsTests(unittest.TestCase):
|
|||||||
self.assertTrue(any("tags[2] must be a non-empty string" in error for error in errors))
|
self.assertTrue(any("tags[2] must be a non-empty string" in error for error in errors))
|
||||||
|
|
||||||
|
|
||||||
|
class PluginConfigAccessorTests(unittest.TestCase):
|
||||||
|
def test_accepts_universal_accessor(self) -> None:
|
||||||
|
self.assertEqual(
|
||||||
|
validate_plugins.obsolete_config_accessors('local value = noctalia.getConfig("key")'),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rejects_every_entry_specific_alias(self) -> None:
|
||||||
|
source = "\n".join(
|
||||||
|
[
|
||||||
|
'barWidget.getConfig("one")',
|
||||||
|
'desktopWidget.getConfig("two")',
|
||||||
|
'panel . getConfig("three")',
|
||||||
|
'launcher.getConfig("four")',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
validate_plugins.obsolete_config_accessors(source),
|
||||||
|
[
|
||||||
|
("barWidget.getConfig", 1),
|
||||||
|
("desktopWidget.getConfig", 2),
|
||||||
|
("panel.getConfig", 3),
|
||||||
|
("launcher.getConfig", 4),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_ignores_comments_and_strings(self) -> None:
|
||||||
|
source = "\n".join(
|
||||||
|
[
|
||||||
|
'-- barWidget.getConfig("comment")',
|
||||||
|
'--[[ panel.getConfig("block comment") ]]',
|
||||||
|
'local text = "launcher.getConfig(\\\"string\\\")"',
|
||||||
|
'local block = [[desktopWidget.getConfig("long string")]]',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.assertEqual(validate_plugins.obsolete_config_accessors(source), [])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -151,6 +151,9 @@ HTML_RE = re.compile(
|
|||||||
)
|
)
|
||||||
INLINE_CODE_RE = re.compile(r"(?<!`)(`+)(?!`)(.*?)(?<!`)\1(?!`)", re.DOTALL)
|
INLINE_CODE_RE = re.compile(r"(?<!`)(`+)(?!`)(.*?)(?<!`)\1(?!`)", re.DOTALL)
|
||||||
FENCE_OPEN_RE = re.compile(r"^ {0,3}(`{3,}|~{3,})")
|
FENCE_OPEN_RE = re.compile(r"^ {0,3}(`{3,}|~{3,})")
|
||||||
|
OBSOLETE_CONFIG_ACCESSOR_RE = re.compile(
|
||||||
|
r"\b(barWidget|desktopWidget|panel|launcher)\s*\.\s*getConfig\b"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_non_empty_string(value: Any) -> bool:
|
def is_non_empty_string(value: Any) -> bool:
|
||||||
@@ -208,6 +211,62 @@ def raw_html_line(markdown: str) -> int | None:
|
|||||||
return text.count("\n", 0, match.start()) + 1
|
return text.count("\n", 0, match.start()) + 1
|
||||||
|
|
||||||
|
|
||||||
|
def obsolete_config_accessors(source: str) -> list[tuple[str, int]]:
|
||||||
|
"""Find removed entry-specific getConfig aliases outside Luau comments and strings."""
|
||||||
|
visible = list(source)
|
||||||
|
length = len(source)
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
def mask(start: int, end: int) -> None:
|
||||||
|
for offset in range(start, end):
|
||||||
|
if visible[offset] not in "\r\n":
|
||||||
|
visible[offset] = " "
|
||||||
|
|
||||||
|
while index < length:
|
||||||
|
if source.startswith("--[[", index):
|
||||||
|
end = source.find("]]", index + 4)
|
||||||
|
end = length if end == -1 else end + 2
|
||||||
|
mask(index, end)
|
||||||
|
index = end
|
||||||
|
continue
|
||||||
|
|
||||||
|
if source.startswith("--", index):
|
||||||
|
end = source.find("\n", index + 2)
|
||||||
|
end = length if end == -1 else end
|
||||||
|
mask(index, end)
|
||||||
|
index = end
|
||||||
|
continue
|
||||||
|
|
||||||
|
if source.startswith("[[", index):
|
||||||
|
end = source.find("]]", index + 2)
|
||||||
|
end = length if end == -1 else end + 2
|
||||||
|
mask(index, end)
|
||||||
|
index = end
|
||||||
|
continue
|
||||||
|
|
||||||
|
if source[index] in "\"'":
|
||||||
|
quote = source[index]
|
||||||
|
end = index + 1
|
||||||
|
while end < length:
|
||||||
|
if source[end] == "\\" and end + 1 < length:
|
||||||
|
end += 2
|
||||||
|
continue
|
||||||
|
end += 1
|
||||||
|
if source[end - 1] == quote:
|
||||||
|
break
|
||||||
|
mask(index, end)
|
||||||
|
index = end
|
||||||
|
continue
|
||||||
|
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
code = "".join(visible)
|
||||||
|
return [
|
||||||
|
(f"{match.group(1)}.getConfig", code.count("\n", 0, match.start()) + 1)
|
||||||
|
for match in OBSOLETE_CONFIG_ACCESSOR_RE.finditer(code)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def webp_dimensions(header: bytes) -> tuple[int, int] | None:
|
def webp_dimensions(header: bytes) -> tuple[int, int] | None:
|
||||||
"""Width and height from a WebP header, or None if it is not one we can read.
|
"""Width and height from a WebP header, or None if it is not one we can read.
|
||||||
|
|
||||||
@@ -880,6 +939,20 @@ class Validator:
|
|||||||
if line is not None:
|
if line is not None:
|
||||||
self.add_error(readme, f"raw HTML on line {line} is not allowed; use Markdown instead")
|
self.add_error(readme, f"raw HTML on line {line} is not allowed; use Markdown instead")
|
||||||
|
|
||||||
|
def validate_luau_api(self, plugin_dir: Path) -> None:
|
||||||
|
for source_path in sorted(plugin_dir.rglob("*.luau")):
|
||||||
|
try:
|
||||||
|
source = source_path.read_text(encoding="utf-8")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
self.add_error(source_path, "must be UTF-8 text")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for accessor, line in obsolete_config_accessors(source):
|
||||||
|
self.add_error(
|
||||||
|
source_path,
|
||||||
|
f"'{accessor}' on line {line} was removed; use noctalia.getConfig",
|
||||||
|
)
|
||||||
|
|
||||||
def validate_no_symlinks(self, manifest_path: Path, plugin_dir: Path) -> None:
|
def validate_no_symlinks(self, manifest_path: Path, plugin_dir: Path) -> None:
|
||||||
for path in plugin_dir.rglob("*"):
|
for path in plugin_dir.rglob("*"):
|
||||||
if path.is_symlink():
|
if path.is_symlink():
|
||||||
@@ -897,6 +970,7 @@ class Validator:
|
|||||||
self.validate_required_files(manifest_path, plugin_dir)
|
self.validate_required_files(manifest_path, plugin_dir)
|
||||||
self.validate_thumbnail(manifest_path, plugin_dir)
|
self.validate_thumbnail(manifest_path, plugin_dir)
|
||||||
self.validate_readme(plugin_dir)
|
self.validate_readme(plugin_dir)
|
||||||
|
self.validate_luau_api(plugin_dir)
|
||||||
self.validate_no_symlinks(manifest_path, plugin_dir)
|
self.validate_no_symlinks(manifest_path, plugin_dir)
|
||||||
|
|
||||||
if "setting" in manifest:
|
if "setting" in manifest:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ id = "oldirtty/color_picker"
|
|||||||
name = "Color Picker"
|
name = "Color Picker"
|
||||||
description = "Pick a color from your screen with hyprpicker."
|
description = "Pick a color from your screen with hyprpicker."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
min_noctalia = "5.0.0"
|
||||||
icon = "palette"
|
icon = "palette"
|
||||||
dependencies = ["hyprpicker"]
|
dependencies = ["hyprpicker"]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
-- Right Click: picks a color directly
|
-- Right Click: picks a color directly
|
||||||
-- and copies the hex to clipboard (no panel).
|
-- and copies the hex to clipboard (no panel).
|
||||||
|
|
||||||
local glyph = barWidget.getConfig("glyph")
|
local glyph = noctalia.getConfig("glyph")
|
||||||
local tr_color_picker = noctalia.tr("color_picker");
|
local tr_color_picker = noctalia.tr("color_picker");
|
||||||
|
|
||||||
local function render()
|
local function render()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
local showText = barWidget.getConfig("show_text")
|
local showText = noctalia.getConfig("show_text")
|
||||||
local notifyChange = barWidget.getConfig("notify_change")
|
local notifyChange = noctalia.getConfig("notify_change")
|
||||||
|
|
||||||
local currentKeymode = "default"
|
local currentKeymode = "default"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
id = "gambled23/mangowm-keymode"
|
id = "gambled23/mangowm-keymode"
|
||||||
name = "Mangowm Keymode"
|
name = "Mangowm Keymode"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
min_noctalia = "5.0.0"
|
||||||
author = "gambled23"
|
author = "gambled23"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
id = "joshuaslate/shelly"
|
id = "joshuaslate/shelly"
|
||||||
name = "Shelly"
|
name = "Shelly"
|
||||||
icon = "package"
|
icon = "package"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
min_noctalia = "5.0.0"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
author = "joshuaslate"
|
author = "joshuaslate"
|
||||||
|
|||||||
+6
-6
@@ -1,11 +1,11 @@
|
|||||||
--!nonstrict
|
--!nonstrict
|
||||||
local glyph = barWidget.getConfig("glyph")
|
local glyph = noctalia.getConfig("glyph")
|
||||||
local color = barWidget.getConfig("color") or "on_surface"
|
local color = noctalia.getConfig("color") or "on_surface"
|
||||||
local glyphColor = barWidget.getConfig("glyph_color") or color
|
local glyphColor = noctalia.getConfig("glyph_color") or color
|
||||||
local updateError = noctalia.state.get("update_error")
|
local updateError = noctalia.state.get("update_error")
|
||||||
local notifyOnNewUpdates = barWidget.getConfig("notify")
|
local notifyOnNewUpdates = noctalia.getConfig("notify")
|
||||||
local hideWhenUpToDate = barWidget.getConfig("hide_when_up_to_date")
|
local hideWhenUpToDate = noctalia.getConfig("hide_when_up_to_date")
|
||||||
local click_action = barWidget.getConfig("click_action") or "open_gui"
|
local click_action = noctalia.getConfig("click_action") or "open_gui"
|
||||||
local updates = noctalia.state.get("updates") or { Packages = {}, Aur = {}, Flatpak = {} }
|
local updates = noctalia.state.get("updates") or { Packages = {}, Aur = {}, Flatpak = {} }
|
||||||
|
|
||||||
local function countUpdates(scopedUpdates)
|
local function countUpdates(scopedUpdates)
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
id = "neuro/upbeat"
|
id = "neuro/upbeat"
|
||||||
name = "Upbeat"
|
name = "Upbeat"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
min_noctalia = "5.0.0"
|
min_noctalia = "5.0.0"
|
||||||
author = "neuro"
|
author = "neuro"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
+3
-3
@@ -13,10 +13,10 @@ function update()
|
|||||||
local secondsSinceMidnight: number = (os.time() + BIEL_OFFSET_SECONDS) % 86400 -- 86400 = seconds in one day
|
local secondsSinceMidnight: number = (os.time() + BIEL_OFFSET_SECONDS) % 86400 -- 86400 = seconds in one day
|
||||||
local totalCentibeats: number = math.floor(secondsSinceMidnight / SECONDS_PER_CENTIBEAT)
|
local totalCentibeats: number = math.floor(secondsSinceMidnight / SECONDS_PER_CENTIBEAT)
|
||||||
-- define display of subbeat toggle
|
-- define display of subbeat toggle
|
||||||
local useCentibeats: boolean = barWidget.getConfig("show_centibeats")
|
local useCentibeats: boolean = noctalia.getConfig("show_centibeats")
|
||||||
-- define display of @beats toggle
|
-- define display of @beats toggle
|
||||||
local showSuffix: boolean = barWidget.getConfig("beat_display")
|
local showSuffix: boolean = noctalia.getConfig("beat_display")
|
||||||
local timeFormatToggle: boolean = barWidget.getConfig("time_format_toggle")
|
local timeFormatToggle: boolean = noctalia.getConfig("time_format_toggle")
|
||||||
local checkValue: number = useCentibeats and totalCentibeats or math.floor(totalCentibeats / 100)
|
local checkValue: number = useCentibeats and totalCentibeats or math.floor(totalCentibeats / 100)
|
||||||
-- layout updates when values tick
|
-- layout updates when values tick
|
||||||
if checkValue ~= lastValue then
|
if checkValue ~= lastValue then
|
||||||
|
|||||||
Reference in New Issue
Block a user