from __future__ import annotations
from typing import List, Set, Tuple, cast
import logging
import fluent.syntax.ast as FTL
from fluent.migrate.util import fold
from .transforms import Source
from .util import get_message, skeleton
from .errors import (
EmptyLocalizationError,
UnreadableReferenceError,
)
from ._context import InternalContext
__all__ = [
"EmptyLocalizationError",
"UnreadableReferenceError",
"MigrationContext",
]
class MigrationContext(InternalContext):
def __init__(
self,
locale: str,
reference_dir: str,
localization_dir: str,
enforce_translated=False,
):
super().__init__(
locale,
enforce_translated=enforce_translated,
)
self.locale = locale
self.reference_dir = reference_dir
self.localization_dir = localization_dir
self.dependencies = {}
def add_transforms(
self, target: str, reference: str, transforms: List[FTL.Message | FTL.Term]
):
def get_sources(acc, cur):
if isinstance(cur, Source):
acc.add((cur.path, cur.key))
return acc
if self.reference_dir is None:
reference_ast = self.reference_resources.get(target)
if reference_ast is None:
reference_ast = FTL.Resource()
reference_ast.body.extend(skeleton(transform) for transform in transforms)
else:
reference_ast = self.read_reference_ftl(reference)
self.reference_resources[target] = reference_ast
for node in transforms:
ident = cast(str, node.id.name)
dependencies = cast(Set[Tuple[str, Source]], fold(get_sources, node, set()))
self.dependencies[(target, ident)] = dependencies
if self.reference_dir is None:
continue
if get_message(reference_ast.body, ident) is None:
logger = logging.getLogger("migrate")
logger.warning(
'{} "{}" was not found in {}'.format(
type(node).__name__, ident, reference
)
)
expected_paths = set()
for dependencies in self.dependencies.values():
for path in {path for path, _ in dependencies}:
expected_paths.add(path)
self.maybe_add_localization(path)
if len(expected_paths) > 0 and len(self.localization_resources) == 0:
error_message = "No localization files were found"
logging.getLogger("migrate").error(error_message)
raise EmptyLocalizationError(error_message)
path_transforms = self.transforms.setdefault(target, [])
path_transforms += transforms
if target not in self.target_resources:
target_ast = self.read_localization_ftl(target)
self.target_resources[target] = target_ast