<commit_before>import json
import os
import posixpath
import re

from static_precompiler import exceptions, settings, utils

from . import base

__all__ = (
    "LESS",
)


class LESS(base.BaseCompiler):

    name = "less"
    supports_dependencies = True
    input_extension = "less"
    output_extension = "css"

    IMPORT_RE = re.compile(r"@import\s+(.+?)\s*;", re.DOTALL)
    IMPORT_ITEM_RE = re.compile(r"([\"'])(.+?)\1")

    def __init__(self, executable=settings.LESS_EXECUTABLE, sourcemap_enabled=False):
        self.executable = executable
        self.is_sourcemap_enabled = sourcemap_enabled
        super(LESS, self).__init__()

    def should_compile(self, source_path, from_management=False):
        # Do not compile the files that start with "_" if run from management
        if from_management and os.path.basename(source_path).startswith("_"):
            return False
        return super(LESS, self).should_compile(source_path, from_management)

    def compile_file(self, source_path):
        full_source_path = self.get_full_source_path(source_path)
        full_output_path = self.get_full_output_path(source_path)

        # `cwd` is a directory containing `source_path`.
        # Ex: source_path = '1/2/3', full_source_path = '/abc/1/2/3' -> cwd = '/abc'
        cwd = os.path.normpath(os.path.join(full_source_path, *([".."] * len(source_path.split("/")))))

        args = [
            self.executable
        ]
        if self.is_sourcemap_enabled:
            args.extend([
                "--source-map"
            ])

        args.extend([
            self.get_full_source_path(source_path),
            full_output_path,
        ])
        out, errors = utils.run_command(args, cwd=cwd)
        if errors:
            raise exceptions.StaticCompilationError(errors)

        utils.convert_urls(full_output_path, source_path)

        if self.is_sourcemap_enabled:
            sourcemap_full_path = full_output_path + ".map"

            with open(sourcemap_full_path) as sourcemap_file:
                sourcemap = json.loads(sourcemap_file.read())

            # LESS, unlike SASS, can't add correct relative paths in source map when the compiled file
            # is not in the same dir as the source file. We fix it here.
            sourcemap["sourceRoot"] = "../" * len(source_path.split("/")) + posixpath.dirname(source_path)

            sourcemap["file"] = posixpath.basename(source_path)

            with open(sourcemap_full_path, "w") as sourcemap_file:
                sourcemap_file.write(json.dumps(sourcemap))

        return self.get_output_path(source_path)

    def compile_source(self, source):
        args = [
            self.executable,
            "-"
        ]

        out, errors = utils.run_command(args, source)

        if errors:
            raise exceptions.StaticCompilationError(errors)

        return out

    def find_imports(self, source):
        """ Find the imported files in the source code.

        :param source: source code
        :type source: str
        :returns: list of str

        """
        imports = set()
        for import_string in self.IMPORT_RE.findall(source):<commit_msg>Fix "file" attribute in LESS source map – it should be the name of compiled file, not the source file<commit_after>import json
import os
import posixpath
import re

from static_precompiler import exceptions, settings, utils

from . import base

__all__ = (
    "LESS",
)


class LESS(base.BaseCompiler):

    name = "less"
    supports_dependencies = True
    input_extension = "less"
    output_extension = "css"

    IMPORT_RE = re.compile(r"@import\s+(.+?)\s*;", re.DOTALL)
    IMPORT_ITEM_RE = re.compile(r"([\"'])(.+?)\1")

    def __init__(self, executable=settings.LESS_EXECUTABLE, sourcemap_enabled=False):
        self.executable = executable
        self.is_sourcemap_enabled = sourcemap_enabled
        super(LESS, self).__init__()

    def should_compile(self, source_path, from_management=False):
        # Do not compile the files that start with "_" if run from management
        if from_management and os.path.basename(source_path).startswith("_"):
            return False
        return super(LESS, self).should_compile(source_path, from_management)

    def compile_file(self, source_path):
        full_source_path = self.get_full_source_path(source_path)
        full_output_path = self.get_full_output_path(source_path)

        # `cwd` is a directory containing `source_path`.
        # Ex: source_path = '1/2/3', full_source_path = '/abc/1/2/3' -> cwd = '/abc'
        cwd = os.path.normpath(os.path.join(full_source_path, *([".."] * len(source_path.split("/")))))

        args = [
            self.executable
        ]
        if self.is_sourcemap_enabled:
            args.extend([
                "--source-map"
            ])

        args.extend([
            self.get_full_source_path(source_path),
            full_output_path,
        ])
        out, errors = utils.run_command(args, cwd=cwd)
        if errors:
            raise exceptions.StaticCompilationError(errors)

        utils.convert_urls(full_output_path, source_path)

        if self.is_sourcemap_enabled:
            sourcemap_full_path = full_output_path + ".map"

            with open(sourcemap_full_path) as sourcemap_file:
                sourcemap = json.loads(sourcemap_file.read())

            # LESS, unlike SASS, can't add correct relative paths in source map when the compiled file
            # is not in the same dir as the source file. We fix it here.
            sourcemap["sourceRoot"] = "../" * len(source_path.split("/")) + posixpath.dirname(source_path)

            sourcemap["file"] = posixpath.basename(full_output_path)

            with open(sourcemap_full_path, "w") as sourcemap_file:
                sourcemap_file.write(json.dumps(sourcemap))

        return self.get_output_path(source_path)

    def compile_source(self, source):
        args = [
            self.executable,
            "-"
        ]

        out, errors = utils.run_command(args, source)

        if errors:
            raise exceptions.StaticCompilationError(errors)

        return out

    def find_imports(self, source):
        """ Find the imported files in the source code.

        :param source: source code
        :type source: str
        :returns: list of str

        """
        imports = set()
        for import_string in self.IMPORT_RE.findall(source):
{'fraction_non_alphanumeric': 0.10395655546935609, 'fraction_numerical': 0.0021722265321955005, 'mean_word_length': 2.4693218514531754, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6523434', 'n_tokens_mistral': 1950, 'n_tokens_neox': 1905, 'n_words': 434}