Repository: opencv/opencv
File: modules/js/generator/embindgen.py (Python)

Code before:
        self.namespaces = {}
        self.enums = {}  # FIXIT 'enums' should belong to 'namespaces'

        self.parser = hdr_parser.CppHeaderParser(
            preprocessor_definitions=preprocessor_definitions
        )
        self.class_idx = 0

    def _is_string_type(self, tp):
        """
        Conservative check whether `tp` represents a string-like type.

        We normalize via type_dict (so aliases like 'String' or 'string'
        map to 'std::string') and then check a few safe patterns.
        """
        if not tp:
            return False
        # Normalize aliases mapped in type_dict (keep original if not present)
        norm = type_dict.get(tp, tp).strip()
        # Strip common qualifiers
        norm = norm.replace('const ', '').replace('&', '').replace('*', '').strip()
        if norm == 'std::string' or norm == 'cv::String':
            return True
        # handle std::basic_string<char, ...>
        if 'basic_string' in norm and 'char' in norm:
            return True
        return False

    def add_class(self, stype, name, decl):
        class_info = ClassInfo(name, decl)
        class_info.decl_idx = self.class_idx
        self.class_idx += 1

        if class_info.name in self.classes:
            print("Generator error: class %s (cpp_name=%s) already exists" \
                  % (class_info.name, class_info.cname))
            sys.exit(-1)
        self.classes[class_info.name] = class_info

    def resolve_class_inheritance(self):
        new_classes = {}
        for name, class_info in self.classes.items():

            if not hasattr(class_info, 'bases'):
                new_classes[name] = class_info
                continue # not class

            if class_info.bases:
                chunks = class_info.bases[0].split('::')
                base = '_'.join(chunks)
                while base not in self.classes and len(chunks) > 1:

Review comment (suggestion):
just `char` filed (integer value 0..255 / -128..127) will be handled as string too.

Code after:
        self.namespaces = {}
        self.enums = {}  # FIXIT 'enums' should belong to 'namespaces'

        self.parser = hdr_parser.CppHeaderParser(
            preprocessor_definitions=preprocessor_definitions
        )
        self.class_idx = 0

    def _is_string_type(self, tp: str) -> bool:
        """Check if a type should be treated as string in bindings."""
        string_types = {
            "std::string",
            "char",
            "signed char",
            "unsigned char",
        }
        return tp in string_types

    def _generate_class_properties(self, class_info, class_bindings):
        # Generate bindings for properties
        for prop in class_info.props:
            if prop.tp in type_dict and not self._is_string_type(prop.tp):
                _class_property = class_property_enum_template
            else:
                _class_property = class_property_template

            class_bindings.append(_class_property.substitute(
                js_name=prop.name,
                cpp_name='::'.join([class_info.cname, prop.name])
            ))

    def add_class(self, stype, name, decl):
        class_info = ClassInfo(name, decl)
        class_info.decl_idx = self.class_idx
        self.class_idx += 1

        if class_info.name in self.classes:
            print("Generator error: class %s (cpp_name=%s) already exists" \
                  % (class_info.name, class_info.cname))
            sys.exit(-1)
        self.classes[class_info.name] = class_info

    def resolve_class_inheritance(self):
        new_classes = {}
        for name, class_info in self.classes.items():

            if not hasattr(class_info, 'bases'):
                new_classes[name] = class_info
                continue # not class

            if class_info.bases: