File treesitter_grammar.req of Package tree-sitter

#!/usr/bin/python3
"""Scan grammar JavaScript sources for their dependencies"""

# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2024 Björn Bidar

# pylint: disable=invalid-name


import platform
import fileinput
import re
from typing import Optional
from pathlib import Path


if platform.sys.version_info.minor < 9:
    def remove_prefix(text, prefix):
        if text.startswith(prefix):
            return text[len(prefix):]
        return text
    def remove_suffix(text, suffix):
        if text.endswith(suffix):
            return text[:-len(suffix):]
        return text

treeSitterGrammarSrcPath  = "/usr/include/tree_sitter"
treeSitterGrammarSymbolToken  = "treesitter_grammar_src"
grammarPaths = []

def resolveFile(grammarFile: str) -> str:
    """Resolve GRAMMARFILE from grammarPaths return found file"""
    fullGrammarFilePath = Path(grammarFile)
    currentGrammarPath = fullGrammarFilePath.parent
    currentGrammarFile = Path(grammarFile)
    if currentGrammarPath != Path('.') and currentGrammarPath.parts[0] == "..":
        # resolve path relative to file found last
        currentGrammarPath = grammarPaths[-1] / fullGrammarFilePath
        if not currentGrammarPath.exists():
            return False
        return currentGrammarPath
    if currentGrammarPath.is_absolute():
        grammarPaths.append(currentGrammarPath)
        if Path(grammarFile).exists():
            return fullGrammarFilePath
    for path in grammarPaths:
        maybeFound = path / currentGrammarFile
        if maybeFound.exists():
            return maybeFound.exists()
    return False

def dummyRequire(requiredFile_fd: str, maxDepth: Optional[int] = 5 ) -> str:
    """Dummy version of node's require function that spits out dependency symbols"""
    if maxDepth <= 0:
        return

    if not requiredFile_fd.endswith(".js"):
        # Append .js to required file name in case is not specified
        # we have to remove .js suffix later in any case.
        requiredFile_fd+=".js"

    resolvedFile_fd = resolveFile(requiredFile_fd)
    if resolvedFile_fd:
        try:
            with open(resolvedFile_fd, mode='r', encoding='utf8') as requiredFile:
                for r_line in requiredFile:
                    require_re = r'.*require\((.*)\).*'
                    requiredLvl2 = re.match(require_re, r_line)
                    #print(r_line)
                    if requiredLvl2 is not None:
                        if platform.sys.version_info.minor < 9:
                            requiredLvl2_grp_cleaned = \
                                remove_suffix(remove_prefix(requiredLvl2.group(1), "'"), "'")
                            requiredLvl2_grp_cleaned = \
                                remove_suffix(remove_prefix(requiredLvl2_grp_cleaned, "\""),
                                              "\"")
                        else:
                            requiredLvl2_grp_cleaned = \
                                requiredLvl2.group(1).removeprefix("'").removesuffix("'")
                            requiredLvl2_grp_cleaned = \
                                requiredLvl2_grp_cleaned.removeprefix("\"").removesuffix("\"")
                        if not requiredLvl2_grp_cleaned.split('/')[0] == "..":
                            # Don't emit dependencies which are local
                            pass
                        dummyRequire(requiredLvl2_grp_cleaned, maxDepth - 1)
        except FileNotFoundError:
            pass
    else:
        if maxDepth == 5:
            # In case we immediately fail to open the first grammar source file
            return
        # We only want to resolve dependencies outside of the package
        print(f"{treeSitterGrammarSymbolToken}({Path(requiredFile_fd).parent})")

for line in fileinput.input():
    line = line.rstrip('\n')
    if line.endswith('.js'):
        dummyRequire(line)
openSUSE Build Service is sponsored by