Skip to content

Constants

gllm_docproc.utils.id_regulation.constants

Shared constants for Indonesian regulation document processing.

Centralises all regex patterns, lookup tables, and enum types used by both the IDRegulationParser and the IDRegulationChunker so neither stage needs to import from the other. IDRegulationParser annotates each parsed element with structure metadata; IDRegulationChunker groups those pre-tagged elements into per-article output chunks.

AMENDMENT_CONTAINER_CITATION_RE = re.compile('(?:Undang\\s*-\\s*Undang|Peraturan|Instruksi|Keputusan)[^:]*?Nomor\\s+\\S+\\s+Tahun\\s+\\d{4}', re.IGNORECASE) module-attribute

AMENDMENT_CONTAINER_LEAD_RE = re.compile('^(?:Pasal|Bagian|BAB|Bab|Paragraf|Di\\s*antara|Setelah|Judul|Penjelasan|Lampiran)\\b|\\b(?:Beberapa\\s+ketentuan|Ketentuan)\\b', re.IGNORECASE) module-attribute

AMENDMENT_CONTAINER_TAIL_RE = re.compile('\\b(?:diubah|dihapus|disisipkan|ditambahkan)\\b(?:[^:]*?\\bsebagai\\s+berikut\\b)?\\s*:\\s*$', re.IGNORECASE) module-attribute

AMENDMENT_DECLARATION_RE = re.compile(f'(?P<opener>beberapa\s+ketentuan\s+dalam)|(?P<verb>(?m:^)[ \t]*mengubah\s+(?={_CITED_REGULATION_TYPE}))', re.IGNORECASE) module-attribute

AMENDMENT_DIRECTIVE_LEAD_RE = re.compile(f'^\d+\.[\s.]*{_AMENDMENT_DIRECTIVE_LEAD_WORDS}\b') module-attribute

AMENDMENT_DIRECTIVE_LEAD_UNNUMBERED_RE = re.compile(f'^{_AMENDMENT_DIRECTIVE_LEAD_WORDS}\b') module-attribute

AMENDMENT_DIRECTIVE_SUBJECT_RE = re.compile('\\bPasal\\s+(?:\\d+[A-Z]?|[IVXLCDM]+)\\b|\\bBAB\\s+[IVXLCDM]+\\b|\\b(?:Bagian|Subbagian)\\s+(?:Ke\\w+|[IVXLCDM]+|\\d+)\\b|\\b(?:Paragraf|Subparagraf)\\s+\\d+\\b', re.IGNORECASE) module-attribute

AMENDMENT_GROUP_EXTRAS_KEYS = tuple(AMENDMENT_GROUP_EXTRAS_KEY_MAP) module-attribute

AMENDMENT_GROUP_EXTRAS_KEY_MAP = {'amendment_group_level': RegulationParserMetadataKey.AMENDMENT_GROUP_LEVEL, 'amendment_group_number': RegulationParserMetadataKey.AMENDMENT_GROUP_NUMBER, 'amendment_group_title': RegulationParserMetadataKey.AMENDMENT_GROUP_TITLE, 'amendment_group_parent_chapter_number': RegulationParserMetadataKey.AMENDMENT_GROUP_PARENT_CHAPTER_NUMBER, 'amendment_group_parent_part_number': RegulationParserMetadataKey.AMENDMENT_GROUP_PARENT_PART_NUMBER, 'amendment_group_parent_paragraph_number': RegulationParserMetadataKey.AMENDMENT_GROUP_PARENT_PARAGRAPH_NUMBER} module-attribute

AMENDMENT_GROUP_LOCATIVE_RE = re.compile(f'\bdalam\s+(?:BAB\s+(?P<chapter>[IVXLCDM]+)|Bagian\s+(?P<part>{_ORDINAL_WORD})|Subparagraf\s+(?P<subparagraph>\d+)|Paragraf\s+(?P<paragraph>\d+))\b', re.IGNORECASE) module-attribute

AMENDMENT_GROUP_SUBJECT_RE = re.compile(f'^\d+\.[\s.]*Judul\s+(?:BAB\s+(?P<chapter>[IVXLCDM]+)|Bagian\s+(?P<part>{_ORDINAL_WORD})|Subparagraf\s+(?P<subparagraph>\d+)|Paragraf\s+(?P<paragraph>\d+))\b', re.IGNORECASE) module-attribute

AMENDMENT_GROUP_SUBJECT_UNNUMBERED_RE = re.compile(f'^Judul\s+(?:BAB\s+(?P<chapter>[IVXLCDM]+)|Bagian\s+(?P<part>{_ORDINAL_WORD})|Subparagraf\s+(?P<subparagraph>\d+)|Paragraf\s+(?P<paragraph>\d+))\b', re.IGNORECASE) module-attribute

AMENDMENT_INDICATOR_RE = re.compile('PERUBAHAN', re.IGNORECASE) module-attribute

AMENDMENT_ITEM_NUMBER_KEY = 'amendment_item_number' module-attribute

AMENDMENT_ITEM_RE = re.compile('^(\\d+)\\.') module-attribute

AMENDMENT_OPERATION_RE = re.compile('\\b(diubah|disisipkan|ditambahkan|dihapus)\\b', re.IGNORECASE) module-attribute

AMENDMENT_QUOTED_ITEM_RE = re.compile('(?m)^\\s*\\d+\\.\\s') module-attribute

AMENDMENT_ROMAN_ARTICLE_BOUND_RE = re.compile(f'(?m)^{ARTICLE_ROMAN_CORE}\s*$') module-attribute

AMENDMENT_SUBJECT_RE = re.compile('^\\s*PERUBAHAN(?:\\s+\\w+){0,2}?\\s+ATAS\\b', re.IGNORECASE) module-attribute

ANNEX_BARE_HEADING_LINE_RE = re.compile(f'^(?:SALINAN\s+)?LAMPIRAN(?:\s+{ANNEX_NUMBER_PATTERN})?\s*$') module-attribute

ANNEX_HEADING_RE = re.compile(f'^(?:SALINAN\s+)?LAMPIRAN(?:\s+{ANNEX_NUMBER_PATTERN})?\s*$', re.IGNORECASE) module-attribute

ANNEX_LOOSE_HEADING_RE = re.compile(f'^(?:SALINAN\s+)?LAMPIRAN\b(?:\s+{ANNEX_NUMBER_PATTERN})?+(?!\s+(?:{ANNEX_NON_HEADING_FOLLOWER_PATTERN})\b)(?!$)', re.IGNORECASE) module-attribute

ANNEX_NON_HEADING_FOLLOWER_PATTERN = 'INI|YANG|SEBAGAIMANA|MERUPAKAN' module-attribute

ANNEX_NUMBER_PATTERN = '(?P<number>(?:[IVXLCDM]+|\\d+)(?:\\.[A-Za-z0-9]+)?)\\b' module-attribute

ANNEX_REFERENCE_HEADING_RE = re.compile(f'^(?:SALINAN\s+)?LAMPIRAN(?:\s+{ANNEX_NUMBER_PATTERN})?\s+(?:PERATURAN|UNDANG-UNDANG|KEPUTUSAN|INSTRUKSI|SURAT\s+EDARAN|KETETAPAN)\b.*\bNOMOR\b', re.IGNORECASE | re.DOTALL) module-attribute

ANNEX_SALINAN_ONLY_RE = re.compile('^SALINAN\\s*$', re.IGNORECASE) module-attribute

ARTICLE_HEADER_CORE = 'Pasal\\s*(\\d+[A-Z]?)' module-attribute

ARTICLE_HEADER_LEAD_RE = re.compile(f'^{ARTICLE_HEADER_CORE}\b') module-attribute

ARTICLE_HEADER_PREFIX_RE = re.compile(f'^{ARTICLE_HEADER_CORE}\b(?!\s+(?:ayat|huruf|angka)\b|[.;,…]|\s+[.;,…]|\s+\.{2,}|\s+[a-z])') module-attribute

ARTICLE_HEADER_RE = re.compile(f'^{ARTICLE_HEADER_CORE}$') module-attribute

ARTICLE_KEYWORD_RE = re.compile('\\bPasal\\b', re.IGNORECASE) module-attribute

ARTICLE_ROMAN_CORE = 'Pasal\\s+([IVXLCDM]+)' module-attribute

ARTICLE_ROMAN_RE = re.compile(f'^{ARTICLE_ROMAN_CORE}$') module-attribute

ARTICLE_SPLIT_RE = re.compile('(?m)(?=^Pasal\\s+\\d+[A-Z]?(?!\\s+ayat)\\b)') module-attribute

ARTICLE_STRUCTURAL_TRAILING_RE = re.compile(f'(?P<title>{_STRUCTURAL_KEYWORD_PATTERN}(?P<title_body>(?:\s.*?\S)?))\s+(?P<pasal>Pasal[ \t]+\d+[A-Z]?)', re.IGNORECASE | re.DOTALL) module-attribute

CHAPTER_RE = re.compile('^BAB\\s+([IVXLCDM]+)(?:\\s+(.+))?') module-attribute

CHUNK_ELEMENT_JSON_KEY = 'element_json' module-attribute

CHUNK_ORDER_KEY = 'order' module-attribute

CITATION_ARTICLE_CLAUSE_RE = re.compile('\\bPasal\\s+(\\d+[A-Z]?)\\s+ayat\\s+\\((\\d+[a-z]?)\\)', re.IGNORECASE) module-attribute

CITATION_ARTICLE_RE = re.compile('\\bPasal\\s+(\\d+[A-Z]?)(?!\\s+ayat\\b)', re.IGNORECASE) module-attribute

CITATION_CLAUSE_ONLY_RE = re.compile('\\bayat\\s+\\((\\d+[a-z]?)\\)', re.IGNORECASE) module-attribute

CITATION_COORDINATED_CLAUSE_RE = re.compile('(?:dan|,|atau|serta)\\s+ayat\\s+\\((\\d+[a-z]?)\\)', re.IGNORECASE) module-attribute

CITATION_TAX_TERM_PREFIX_RE = re.compile('\\b(?:PPh|Pajak\\s+Penghasilan)\\s+$', re.IGNORECASE) module-attribute

CLAUSE_SPLIT_RE = re.compile('(?m)^(\\(\\d+[a-z]?\\))\\s*') module-attribute

CLOSING_START_RE = re.compile('^Agar setiap orang mengetahuinya', re.IGNORECASE) module-attribute

COURT_CONTEXT_RE = re.compile('\\b(Putusan|Mahkamah)\\b', re.IGNORECASE) module-attribute

DECISION_CLAUSE_HEADER_RE = re.compile(f'^(?:Menetapkan\s*:\s*)?(?P<clause_number>{_ORDINAL_WORD})(?:\s*:.*)?$', re.IGNORECASE | re.DOTALL) module-attribute

DECISION_DECLARATION_RE = re.compile('^MEMUTUSKAN[\\s:]*$', re.IGNORECASE) module-attribute

DIRECTIVE_GROUP_SUBJECT_RE = re.compile('^\\s*(?:\\d+\\.\\s*)?(?:Ketentuan\\s+)?(?:Bagian|BAB|Bab|Paragraf|Judul)\\b') module-attribute

DISAHKAN_RE = re.compile('(?m)(?:^|[.;][ \\t]+)[ \\t]*Disahkan[ \\t]+di[ \\t]+(?!dalam\\b)[^\\r\\n]+?(?:\\r?\\n[ \\t]*){0,2}pada[ \\t]+tanggal (\\d{1,2}) (\\w+) (\\d{4})', re.IGNORECASE) module-attribute

DISTRIBUTION_LIST_RE = re.compile('^Tembusan\\b', re.IGNORECASE) module-attribute

DITETAPKAN_RE = re.compile('(?m)(?:^|[.;][ \\t]+)[ \\t]*Ditetapkan[ \\t]+di[ \\t]+(?!dalam\\b)[^\\r\\n]+?(?:\\r?\\n[ \\t]*){0,2}pada[ \\t]+tanggal (\\d{1,2}) (\\w+) (\\d{4})', re.IGNORECASE) module-attribute

DIUNDANGKAN_RE = re.compile('(?m)(?:^|[.;][ \\t]+)[ \\t]*Diundangkan[ \\t]+di[ \\t]+(?!dalam\\b)[^\\r\\n]+?(?:\\r?\\n[ \\t]*){0,2}pada[ \\t]+tanggal (\\d{1,2}) (\\w+) (\\d{4})', re.IGNORECASE) module-attribute

DOCUMENT_TAIL_STRUCTURES = frozenset({RegulationStructure.ENACTMENT_TAIL, RegulationStructure.ANNEX_HEADER, RegulationStructure.ANNEX}) module-attribute

EFFECTIVE_DATE_ESTABLISHED_INDEX = 4 module-attribute

EFFECTIVE_DATE_RE = re.compile('(?:mulai|ini) berlaku pada tanggal (?:(\\d{1,2}) (\\w+) (\\d{4})|(diundangkan)|(ditetapkan|dikeluarkan))', re.IGNORECASE) module-attribute

ELEMENT_COORDINATE_COUNT = 4 module-attribute

ENACTMENT_START_RE = re.compile('^(Agar setiap orang mengetahuinya|Ditetapkan di|Dikeluarkan di|Diundangkan di)', re.IGNORECASE) module-attribute

EXPLANATION_AMENDMENT_ITEM_RE = re.compile('^Pasal\\s+([IVXLCDM]+)\\s+Angka\\s+(\\d+)$', re.IGNORECASE) module-attribute

EXPLANATION_NUMBER_PREFIX_RE = re.compile('^Angka\\s+(\\d+)[\\s.]*([^\\s.].*)$', re.DOTALL) module-attribute

EXPLANATION_NUMBER_RE = re.compile('^Angka\\s+(\\d+)[\\s.]*$') module-attribute

EXPLANATION_RE = re.compile('^PENJELASAN\\b') module-attribute

FIRST_ORDINAL_WORD = 'pertama' module-attribute

GAZETTE_HEADER_START_RE = re.compile('^LEMBARAN NEGARA') module-attribute

GROUP_INSERT_KIND_RE = re.compile('^\\s*\\d+\\s*(?:\\([^)]*\\)\\s*)?(?:Bagian|BAB|Paragraf)\\b', re.IGNORECASE) module-attribute

GROUP_LEVEL_DEPTH = {level: depth for depth, level in (enumerate(AmendmentGroupLevel))} module-attribute

IMAGE_PLACEHOLDER_ELEMENT_RE = re.compile('^\\[image_[^\\]]+\\]$') module-attribute

INDONESIAN_NUMBER_MAP = {'satu': 1, 'dua': 2, 'tiga': 3, 'empat': 4, 'lima': 5, 'enam': 6, 'tujuh': 7, 'delapan': 8, 'sembilan': 9, 'sepuluh': 10, 'sebelas': 11, 'duabelas': 12, 'tigabelas': 13, 'empatbelas': 14, 'limabelas': 15, 'enambelas': 16, 'tujuhbelas': 17, 'delapanbelas': 18, 'sembilanbelas': 19} module-attribute

INSERT_SECTION_HEADER_RES = (re.compile('^Bagian\\s+(?:Ke\\w+|Pertama)\\b'), re.compile('^BAB\\s+[IVXLCDM]+[A-Z]?\\b'), re.compile('^Paragraf\\s+\\d+[A-Z]?\\b')) module-attribute

INSTRUCTION_DECLARATION_RE = re.compile('(?:meng|di)instruksikan\\s*:\\s*$', re.IGNORECASE) module-attribute

INSTRUCTION_HEADER_RE = re.compile(f'^(?:UNTUK\s+)?(?P<instruction_number>{_ORDINAL_WORD})(?:\s*:.*)?$', re.IGNORECASE | re.DOTALL) module-attribute

ISSUANCE_RE = re.compile('(?m)(?:^|[.;][ \\t]+)[ \\t]*Dikeluarkan[ \\t]+di[ \\t]+(?!dalam\\b)[^\\r\\n]+?(?:\\r?\\n[ \\t]*){0,2}pada[ \\t]+tanggal (\\d{1,2}) (\\w+) (\\d{4})', re.IGNORECASE) module-attribute

LEADING_PAGE_NUMBER_RE = re.compile(f'^{PAGE_NUMBER_BOILERPLATE_PATTERN}\s*') module-attribute

LEGAL_BASIS_BLOCK_RE = re.compile('(?i)Mengingat\\s*:\\s*((?:(?!MEMUTUSKAN)[\\s\\S])+)') module-attribute

LEGAL_BASIS_ITEM_SPLIT_RE = re.compile('(?m)(?=^\\d+\\.\\s)') module-attribute

LEGISLATION_TYPE_FROM_NUMBER_RE = re.compile('/([A-Z]+)\\.', re.IGNORECASE) module-attribute

MAX_MARKER_GAP = 2 module-attribute

MIN_LIST_RUN = 3 module-attribute

MONTH_ID = {'januari': 1, 'februari': 2, 'maret': 3, 'april': 4, 'mei': 5, 'juni': 6, 'juli': 7, 'agustus': 8, 'september': 9, 'oktober': 10, 'november': 11, 'desember': 12} module-attribute

NEXT_PAGE_PREVIEW_BOILERPLATE_RE = re.compile(f'{_NEXT_PAGE_PREVIEW_MARKER}?(?:{_NEXT_PAGE_PREVIEW_WORD}|{_NEXT_PAGE_PREVIEW_NUMBER})(?: [^\W_][\w/-]*| ?{_NEXT_PAGE_PREVIEW_BRACKETED_NUMBER})? ?:? ?(?:\. ?\. ?\.|…)') module-attribute

NOMOR_TAHUN_ALPHA_RE = re.compile('NOMOR\\s+(?-i:([A-Z]{1,5}\\.?\\s+\\d+[A-Z]?))\\s+TAHUN\\s+(\\d{4})', re.IGNORECASE) module-attribute

NOMOR_TAHUN_RE = re.compile('NOMOR\\s+(\\d+)' + _NOMOR_TAHUN_QUALIFIER + '\\s+TAHUN\\s+(\\d{4})', re.IGNORECASE) module-attribute

NOMOR_TAHUN_ROMAN_RE = re.compile('NOMOR\\s+(?-i:([IVXLCDM]+))\\s+TAHUN\\s+(\\d{4})', re.IGNORECASE) module-attribute

OFFICIAL_MEMORANDUM_CLOSING_RE = re.compile('^Demikian\\b', re.IGNORECASE) module-attribute

OFFICIAL_MEMORANDUM_INLINE_SUB_POINT_SPLIT_RE = re.compile(f';\s*(?:dan|atau)\s+(?={_OFFICIAL_MEMORANDUM_SUB_POINT_MARKER}\s)', re.IGNORECASE) module-attribute

OFFICIAL_MEMORANDUM_POINT_HEADER_RE = re.compile('^(\\d+)\\.\\s') module-attribute

OFFICIAL_MEMORANDUM_SUB_POINT_HEADER_RE = re.compile(f'^{_OFFICIAL_MEMORANDUM_SUB_POINT_MARKER}\s') module-attribute

OFFICIAL_MEMORANDUM_TITLE_RE = re.compile('^SURAT EDARAN\\b.*NOMOR', re.IGNORECASE | re.DOTALL) module-attribute

OPERATION_KEY = 'operation' module-attribute

OPERATION_MAP = {'diubah': AmendmentOperation.UPDATE, 'disisipkan': AmendmentOperation.INSERT, 'ditambahkan': AmendmentOperation.INSERT, 'dihapus': AmendmentOperation.DELETE} module-attribute

ORDINAL_MARKER_KIND = 'ordinal' module-attribute

OWNED_RELATION_TYPES = frozenset({RelationType.CITES, RelationType.MENTIONS_CONCEPT, RelationType.CONTAINS_OBLIGATION}) module-attribute

PAGE_FURNITURE_DIGIT_RUN_RE = re.compile('\\d+') module-attribute

PAGE_FURNITURE_EXCLUDED_RE = re.compile('^(?:SALINAN\\s+)?(?:LAMPIRAN|PENJELASAN|BAB|Pasal|Bagian|Paragraf|Subparagraf|Angka|Ayat|Huruf)\\b', re.IGNORECASE) module-attribute

PAGE_FURNITURE_IMAGE_SIZE_BUCKET = 10 module-attribute

PAGE_FURNITURE_MAX_OCCURRENCES_PER_PAGE = 1.5 module-attribute

PAGE_FURNITURE_MAX_TEXT_LENGTH = 200 module-attribute

PAGE_FURNITURE_METADATA_KEY = '_regulation_page_furniture' module-attribute

PAGE_FURNITURE_MIN_PAGES = 3 module-attribute

PAGE_FURNITURE_MIN_PAGE_SHARE = 0.5 module-attribute

PAGE_FURNITURE_POSITION_TOLERANCE = 0.03 module-attribute

PAGE_NUMBER_BOILERPLATE_PATTERN = f'[{PAGE_NUMBER_DASHES}]\s*\d+\s*[{PAGE_NUMBER_DASHES}]' module-attribute

PAGE_NUMBER_BOILERPLATE_RE = re.compile(PAGE_NUMBER_BOILERPLATE_PATTERN) module-attribute

PAGE_NUMBER_DASHES = '-–—−' module-attribute

PAGE_SK_STAMP_RE = re.compile('^SK No \\d+ A$', re.IGNORECASE) module-attribute

PARAGRAPH_RE = re.compile('^Paragraf\\s+(\\d+)(?:\\s+(\\S.*))?$') module-attribute

PART_RE = re.compile(f'^Bagian\s+(?P<part_number>{_ORDINAL_WORD})(?:\s+(?!(?-i:[a-z]))(?P<title>.+))?$', re.IGNORECASE) module-attribute

PASAL_DEMI_PASAL_RE = re.compile('PASAL\\s+DEMI\\s+PASAL', re.IGNORECASE) module-attribute

POINT_MARKER_KIND = 'point' module-attribute

PREAMBLE_LIST_RE = re.compile('^(?:Kepada(?:\\s+Yth\\.?)?|Yth\\.|Mengingat)\\s*:?\\s*(?=\\d+\\.\\s|$)', re.IGNORECASE) module-attribute

PRESIDENTIAL_MASTHEAD_BOILERPLATE_RE = re.compile(f'PRESIDEN\s+REPUBLIK\s+INDONESIA(?:\s+{PAGE_NUMBER_BOILERPLATE_PATTERN})?') module-attribute

RATIFICATION_RE = re.compile('^\\s*PENETAPAN\\b.*MENJADI\\s+UNDANG', re.IGNORECASE) module-attribute

REGULATION_CITATION_RE = re.compile(f'\b(?P<type>{_CITED_REGULATION_TYPE}[\w\s-]{0,120}?)\s+Nomor\s+(?P<number>{_CITED_REGULATION_NUMBER}){_NOMOR_TAHUN_QUALIFIER}(?:\s+Tahun\s+(?P<year>\d{4}))?', re.IGNORECASE) module-attribute

REGULATION_NUMBER_RE = re.compile('NOMOR(?:\\s*:\\s*|\\s+)((?:[A-Z]+\\s*-\\s*)?\\d+(?:\\s*/\\s*[\\w.]+)*)', re.IGNORECASE) module-attribute

REGULATION_TITLE_RE = re.compile(f'(?:{_REGULATION_TITLE_START})(?:(?!{_REGULATION_TITLE_STOP}).)+', re.IGNORECASE | re.DOTALL) module-attribute

REVOCATION_ARBITRARY_SCOPE_RE = re.compile('Pasal\\s+(?:\\d+[A-Z]?|[IVXLCDM]+)\\b.*\\bsepanjang\\b|,\\s*sepanjang\\b', re.IGNORECASE) module-attribute

REVOCATION_INDICATOR_RE = re.compile('dicabut\\s+dan\\s+dinyatakan\\s+tidak\\s+berlaku', re.IGNORECASE) module-attribute

REVOCATION_ITEM_SPLIT_RE = re.compile(f'(?m)(?:^|(?<=[:;])\s*)([a-z]+)[.)]\s+{_REVOCATION_ITEM_OPENER}\b', re.IGNORECASE) module-attribute

REVOCATION_SCOPE_CONNECTOR_RE = re.compile('(?:sampai\\s+dengan|dan\\s*/\\s*atau|serta|\\bdan\\b|,|;)$', re.IGNORECASE) module-attribute

REVOCATION_SCOPE_UNIT_LEADING_RE = re.compile(_REVOCATION_SCOPE_UNIT_CORE, re.IGNORECASE) module-attribute

REVOCATION_SCOPE_UNIT_RE = re.compile(_REVOCATION_SCOPE_UNIT_CORE + '$', re.IGNORECASE) module-attribute

SCANNER_WATERMARK_BOILERPLATE_RE = re.compile('(?:Scanned|Digitised|Digitized|Dipindai)\\s+(?:by|with|using|dengan|oleh)\\s+[a-z][\\w.\\- ]{0,24}', re.IGNORECASE) module-attribute

SK_NUMBER_BOILERPLATE_RE = re.compile('SK ?No\\.? ?\\d+ ?[A-Z]?\\.?', re.IGNORECASE) module-attribute

STATE_GAZETTE_CONTEXT_RE = re.compile('(LEMBARAN NEGARA|TAMBAHAN LEMBARAN NEGARA)', re.IGNORECASE) module-attribute

STATE_GAZETTE_DECLARATION_RE = re.compile('LEMBARAN\\s*NEGARA\\s*REPUBLIK\\s*INDONESIA\\s*TAHUN\\s*[0-9]{4}\\s*NOMOR\\s*[0-9]+\\b|TAMBAHAN\\s*LEMBARAN\\s*NEGARA\\s*REPUBLIK\\s*INDONESIA\\s*NOMOR\\s*[0-9]+\\b') module-attribute

STRUCTURAL_ANCHOR_STRUCTURES = frozenset({RegulationStructure.ARTICLE_HEADER, RegulationStructure.POINT_HEADER, RegulationStructure.DECISION_CLAUSE_HEADER, RegulationStructure.INSTRUCTION_HEADER, RegulationStructure.CHAPTER_HEADER, RegulationStructure.ANNEX_HEADER, RegulationStructure.EXPLANATION_ARTICLE_HEADER, RegulationStructure.EXPLANATION_AMENDMENT_TARGET_ARTICLE_HEADER}) module-attribute

STRUCTURAL_METADATA_KEYS = RegulationParserMetadataKey.structural_keys() module-attribute

SUBPARAGRAPH_RE = re.compile('^Subparagraf\\s+(\\d+)(?:\\s+(\\S.*))?$') module-attribute

TARGET_ARTICLE_NUMBER_KEY = 'target_article_number' module-attribute

TARGET_ARTICLE_RE = re.compile('\\bPasal\\s+(\\d+[A-Z]?)\\b') module-attribute

TENTANG_RE = re.compile('(?i)TENTANG\\s+((?:(?!DENGAN RAHMAT|MENIMBANG|MENGINGAT|MEMUTUSKAN|PRESIDEN REPUBLIK INDONESIA,)[\\s\\S])+)') module-attribute

TETAP_ONLY_ITEM_RE = re.compile('^(\\d+)\\.[^.]*\\btetap\\b', re.IGNORECASE) module-attribute

YEAR_RE = re.compile('\\b(20\\d{2}|19\\d{2})\\b') module-attribute

_AMENDMENT_DIRECTIVE_LEAD_WORDS = '(?:Ketentuan|Pasal|Bagian|BAB|Bab|Paragraf|Di\\s*antara|Setelah|Judul|Penjelasan|Lampiran)' module-attribute

_CITED_REGULATION_NUMBER = '(?:[A-Z]+[-.])?\\d+(?:\\s*/\\s*[\\w.]+)*' module-attribute

_CITED_REGULATION_TYPE = '(?:Peraturan|Undang-Undang|Keputusan|Instruksi|Surat\\s+Edaran|Ketetapan)' module-attribute

_NEXT_PAGE_PREVIEW_BRACKETED_NUMBER = '\\(\\d+[a-z]?\\)?' module-attribute

_NEXT_PAGE_PREVIEW_MARKER = '(?:\\(\\d+[a-z]?(?:\\) ?| )|(?:\\d+\\.|[IVXLCDM]+\\.|[A-Za-z]\\.) ?)' module-attribute

_NEXT_PAGE_PREVIEW_NUMBER = '(?:Rp ?)?\\d+(?:[.,]\\d+)*(?: \\([^\\W\\d_]+(?: [^\\W\\d_]+){0,3}\\))?' module-attribute

_NEXT_PAGE_PREVIEW_WORD = '[^\\W\\d_][\\w/-]*' module-attribute

_NOMOR_TAHUN_QUALIFIER = '(?:\\s+[A-Za-z]{2,4}\\.)?' module-attribute

_NUMBER_VOCAB = '|'.join(list(INDONESIAN_NUMBER_MAP.keys()) + ['belas', 'puluh']) module-attribute

_OFFICIAL_MEMORANDUM_SUB_POINT_MARKER = '(?:[a-z]+[.)]|\\d+\\))' module-attribute

_ORDINAL_NUMBER_WORD = f'(?:ke)?(?:{_NUMBER_VOCAB})(?:\s+(?:{_NUMBER_VOCAB})\b)*+' module-attribute

_ORDINAL_WORD = f'(?:{FIRST_ORDINAL_WORD}|{_ORDINAL_NUMBER_WORD})' module-attribute

_REGULATION_TITLE_START = 'UNDANG-UNDANG|PERATURAN|SURAT EDARAN|KEPUTUSAN|INSTRUKSI MENTERI|INSTRUKSI PRESIDEN' module-attribute

_REGULATION_TITLE_STOP = 'DENGAN RAHMAT|MENIMBANG|MENGINGAT|MEMUTUSKAN|PRESIDEN REPUBLIK INDONESIA,' module-attribute

_REVOCATION_ITEM_OPENER = f'(?:{_CITED_REGULATION_TYPE}|Paragraf|Subparagraf|Lampiran|Bab|Bagian|Pasal)' module-attribute

_REVOCATION_SCOPE_UNIT_CORE = '(?:Pasal\\s+(?P<pasal_num>\\d+[A-Z]?|[IVXLCDM]+)|ayat\\s*\\(\\s*\\d+\\s*\\)|huruf\\s+[A-Za-z]{1,3}|angka\\s+(?:\\d+|[IVXLCDM]+)|(?P<scope_anchor>Subbagian|Subparagraf|Bagian|Bab|Paragraf|Lampiran)(?:\\s+(?:Ke\\w+|[IVXLCDM]+|\\d+))?)' module-attribute

_STRUCTURAL_KEYWORD_PATTERN = f'(?:BAB\s+[IVXLCDM]+(?-i:[A-Z])?|Bagian\s+{_ORDINAL_WORD}(?:\s+(?-i:[A-Z]))?|Subparagraf(?:\s+(?-i:[A-Z]))?|Paragraf\s+\d+(?-i:[A-Z])?)' module-attribute

AmendmentExtrasKeys

Bases: StrEnum

Keys of an ArticleGroup.amendment_extras dict, set by a grouper and read by the chunker.

Grouped here rather than left as loose constants because a grouper and the chunker have to agree on every one of them. StrEnum members double as dict keys and compare equal to the plain strings already in committed fixtures.

AMENDS_REGULATION_ID = 'amends_regulation_id' class-attribute instance-attribute

ITEM_NUMBER = 'amendment_item_number' class-attribute instance-attribute

OPERATION = 'operation' class-attribute instance-attribute

TARGET_ARTICLE_NUMBER = 'target_article_number' class-attribute instance-attribute

AmendmentGroupLevel

Bases: StrEnum

Structural level of a BAB/Bagian/Paragraf/Subparagraf group an amendment item targets.

Distinguishes a targeted group's own hierarchy level (see IDRegulationParser's regulation_amendment_group_level metadata field) from the article-level AmendmentOperation -- a single INSERT item can introduce a whole new chapter/part/paragraph, and this is the vocabulary for which level it is.

Members are declared outermost-first; GROUP_LEVEL_DEPTH below reads that nesting order.

CHAPTER = 'chapter' class-attribute instance-attribute

PARAGRAPH = 'paragraph' class-attribute instance-attribute

PART = 'part' class-attribute instance-attribute

SUBPARAGRAPH = 'subparagraph' class-attribute instance-attribute

AmendmentOperation

Bases: StrEnum

Amendment operation types for Indonesian regulations.

DELETE = 'delete' class-attribute instance-attribute

INSERT = 'insert' class-attribute instance-attribute

UPDATE = 'update' class-attribute instance-attribute

CitationType

Bases: StrEnum

Citation types for regulation cross-references.

INTRA = 'intra' class-attribute instance-attribute

NodeLabel

Bases: StrEnum

Neo4j node labels for the Indonesian regulation graph. See ONTOLOGY.md.

ARTICLE = 'Article' class-attribute instance-attribute

ARTICLE_VERSION = 'ArticleVersion' class-attribute instance-attribute

CHAPTER = 'Chapter' class-attribute instance-attribute

CHUNK = 'Chunk' class-attribute instance-attribute

CLAUSE = 'Clause' class-attribute instance-attribute

CONCEPT = 'Concept' class-attribute instance-attribute

EXPLANATION = 'Explanation' class-attribute instance-attribute

OBLIGATION = 'Obligation' class-attribute instance-attribute

PARAGRAPH = 'Paragraph' class-attribute instance-attribute

PART = 'Part' class-attribute instance-attribute

REGULATION = 'Regulation' class-attribute instance-attribute

SUBPARAGRAPH = 'Subparagraph' class-attribute instance-attribute

RegulationParserMetadataKey

Bases: StrEnum

Keys IDRegulationParser writes into each element's metadata dict.

structural_keys() returns members after STRUCTURE and before TITLE. TITLE through VERSION_TAG are document-level identity keys. AMENDS_REGULATION is the legacy singular key kept for older persisted metadata.

ABOUT = 'regulation_about' class-attribute instance-attribute

AMENDMENT_GROUP_LEVEL = 'regulation_amendment_group_level' class-attribute instance-attribute

AMENDMENT_GROUP_NUMBER = 'regulation_amendment_group_number' class-attribute instance-attribute

AMENDMENT_GROUP_PARENT_CHAPTER_NUMBER = 'regulation_amendment_group_parent_chapter_number' class-attribute instance-attribute

AMENDMENT_GROUP_PARENT_PARAGRAPH_NUMBER = 'regulation_amendment_group_parent_paragraph_number' class-attribute instance-attribute

AMENDMENT_GROUP_PARENT_PART_NUMBER = 'regulation_amendment_group_parent_part_number' class-attribute instance-attribute

AMENDMENT_GROUP_TITLE = 'regulation_amendment_group_title' class-attribute instance-attribute

AMENDMENT_ITEM_INLINE_BODY = 'regulation_amendment_item_inline_body' class-attribute instance-attribute

AMENDMENT_ITEM_NUMBER = 'regulation_amendment_item_number' class-attribute instance-attribute

AMENDMENT_OPERATION = 'regulation_amendment_operation' class-attribute instance-attribute

AMENDMENT_REGULATION_ID = 'regulation_amendment_regulation_id' class-attribute instance-attribute

AMENDMENT_TARGET = 'regulation_amendment_target' class-attribute instance-attribute

AMENDS_REGULATION = 'regulation_amends_regulation' class-attribute instance-attribute

AMENDS_REGULATIONS = 'regulation_amends_regulations' class-attribute instance-attribute

ANNEX_NUMBER = 'regulation_annex_number' class-attribute instance-attribute

ARTICLE_NUMBER = 'regulation_article_number' class-attribute instance-attribute

CHAPTER_NUMBER = 'regulation_chapter_number' class-attribute instance-attribute

CHAPTER_TITLE = 'regulation_chapter_title' class-attribute instance-attribute

DATE = 'regulation_date' class-attribute instance-attribute

DECISION_CLAUSE_NUMBER = 'regulation_decision_clause_number' class-attribute instance-attribute

EFFECTIVE_DATE = 'regulation_effective_date' class-attribute instance-attribute

ENACTED_ON = 'regulation_enacted_on' class-attribute instance-attribute

ID = 'regulation_id' class-attribute instance-attribute

INSTRUCTION_NUMBER = 'regulation_instruction_number' class-attribute instance-attribute

IS_AMENDMENT = 'regulation_is_amendment' class-attribute instance-attribute

LEGAL_BASES = 'regulation_legal_bases' class-attribute instance-attribute

LEGISLATION_SUB_TYPE = 'regulation_legislation_sub_type' class-attribute instance-attribute

LEGISLATION_TYPE = 'regulation_legislation_type' class-attribute instance-attribute

NUMBER = 'regulation_number' class-attribute instance-attribute

PARAGRAPH_NUMBER = 'regulation_paragraph_number' class-attribute instance-attribute

PARAGRAPH_TITLE = 'regulation_paragraph_title' class-attribute instance-attribute

PART_NUMBER = 'regulation_part_number' class-attribute instance-attribute

PART_TITLE = 'regulation_part_title' class-attribute instance-attribute

POINT_NUMBER = 'regulation_point_number' class-attribute instance-attribute

REVOKES_REGULATIONS = 'regulation_revokes_regulations' class-attribute instance-attribute

STRUCTURE = 'regulation_structure' class-attribute instance-attribute

SUBPARAGRAPH_NUMBER = 'regulation_subparagraph_number' class-attribute instance-attribute

SUBPARAGRAPH_TITLE = 'regulation_subparagraph_title' class-attribute instance-attribute

TITLE = 'regulation_title' class-attribute instance-attribute

VERSION_TAG = 'version_tag' class-attribute instance-attribute

YEAR = 'regulation_year' class-attribute instance-attribute

structural_keys() classmethod

Per-element structural keys: every member after STRUCTURE and before TITLE.

STRUCTURE is written separately by each tagger. Document-level identity keys (TITLE through VERSION_TAG) are stamped identically on every element and are not cleared with the per-element structural fields.

Returns:

Type Description
tuple[RegulationParserMetadataKey, ...]

tuple[RegulationParserMetadataKey, ...]: The structural metadata keys, in enum order.

RegulationStructure

Bases: StrEnum

Structural element types within an Indonesian regulation document.

Used to tag each parsed element with its role in the document hierarchy, from front matter through chapters, parts, paragraphs, articles, body text, amendment directives, explanations, and the enactment tail.

AMENDMENT_GROUP_HEADER = 'amendment_group_header' class-attribute instance-attribute

AMENDMENT_GROUP_TITLE = 'amendment_group_title' class-attribute instance-attribute

AMENDMENT_ITEM_DIRECTIVE = 'amendment_item_directive' class-attribute instance-attribute

AMENDMENT_ITEM_SKIPPED = 'amendment_item_skipped' class-attribute instance-attribute

AMENDMENT_TARGET_ARTICLE_HEADER = 'amendment_target_article_header' class-attribute instance-attribute

ANNEX = 'annex' class-attribute instance-attribute

ANNEX_HEADER = 'annex_header' class-attribute instance-attribute

ARTICLE_HEADER = 'article_header' class-attribute instance-attribute

BODY = 'body' class-attribute instance-attribute

CHAPTER_HEADER = 'chapter_header' class-attribute instance-attribute

CHAPTER_TITLE = 'chapter_title' class-attribute instance-attribute

DECISION_CLAUSE_HEADER = 'decision_clause_header' class-attribute instance-attribute

ENACTMENT_TAIL = 'enactment_tail' class-attribute instance-attribute

EXPLANATION = 'explanation' class-attribute instance-attribute

EXPLANATION_AMENDMENT_ITEM = 'explanation_amendment_item' class-attribute instance-attribute

EXPLANATION_AMENDMENT_TARGET_ARTICLE_HEADER = 'explanation_amendment_target_article_header' class-attribute instance-attribute

EXPLANATION_ARTICLE_HEADER = 'explanation_article_header' class-attribute instance-attribute

EXPLANATION_BODY = 'explanation_body' class-attribute instance-attribute

FRONT_MATTER = 'front_matter' class-attribute instance-attribute

INSTRUCTION_HEADER = 'instruction_header' class-attribute instance-attribute

PARAGRAPH_HEADER = 'paragraph_header' class-attribute instance-attribute

PARAGRAPH_TITLE = 'paragraph_title' class-attribute instance-attribute

PART_HEADER = 'part_header' class-attribute instance-attribute

PART_TITLE = 'part_title' class-attribute instance-attribute

POINT_HEADER = 'point_header' class-attribute instance-attribute

SUBPARAGRAPH_HEADER = 'subparagraph_header' class-attribute instance-attribute

SUBPARAGRAPH_TITLE = 'subparagraph_title' class-attribute instance-attribute

UNKNOWN = 'unknown' class-attribute instance-attribute

RelationType

Bases: StrEnum

Neo4j relationship (edge) types for the Indonesian regulation graph. See ONTOLOGY.md.

AMENDS = 'AMENDS' class-attribute instance-attribute

CITES = 'CITES' class-attribute instance-attribute

CONTAINS_OBLIGATION = 'CONTAINS_OBLIGATION' class-attribute instance-attribute

HAS_ARTICLE = 'HAS_ARTICLE' class-attribute instance-attribute

HAS_CHAPTER = 'HAS_CHAPTER' class-attribute instance-attribute

HAS_CLAUSE = 'HAS_CLAUSE' class-attribute instance-attribute

HAS_EXPLANATION = 'HAS_EXPLANATION' class-attribute instance-attribute

HAS_PARAGRAPH = 'HAS_PARAGRAPH' class-attribute instance-attribute

HAS_PART = 'HAS_PART' class-attribute instance-attribute

HAS_SUBPARAGRAPH = 'HAS_SUBPARAGRAPH' class-attribute instance-attribute

HAS_VERSION = 'HAS_VERSION' class-attribute instance-attribute

IMPLEMENTS = 'IMPLEMENTS' class-attribute instance-attribute

MENTIONS = 'MENTIONS' class-attribute instance-attribute

MENTIONS_CONCEPT = 'MENTIONS_CONCEPT' class-attribute instance-attribute

REVOKES = 'REVOKES' class-attribute instance-attribute

VersionType

Bases: StrEnum

Article version types for Indonesian regulation graph nodes.

AMENDED = 'amended' class-attribute instance-attribute

ORIGINAL = 'original' class-attribute instance-attribute

REPEALED = 'repealed' class-attribute instance-attribute