yuho 5.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- yuho/__init__.py +16 -0
- yuho/ast/__init__.py +196 -0
- yuho/ast/builder.py +926 -0
- yuho/ast/constant_folder.py +280 -0
- yuho/ast/dead_code.py +199 -0
- yuho/ast/exhaustiveness.py +503 -0
- yuho/ast/nodes.py +907 -0
- yuho/ast/overlap.py +291 -0
- yuho/ast/reachability.py +293 -0
- yuho/ast/scope_analysis.py +490 -0
- yuho/ast/transformer.py +490 -0
- yuho/ast/type_check.py +471 -0
- yuho/ast/type_inference.py +425 -0
- yuho/ast/visitor.py +239 -0
- yuho/cli/__init__.py +14 -0
- yuho/cli/commands/__init__.py +1 -0
- yuho/cli/commands/api.py +431 -0
- yuho/cli/commands/ast_viz.py +334 -0
- yuho/cli/commands/check.py +218 -0
- yuho/cli/commands/config.py +311 -0
- yuho/cli/commands/contribute.py +122 -0
- yuho/cli/commands/diff.py +487 -0
- yuho/cli/commands/explain.py +240 -0
- yuho/cli/commands/fmt.py +253 -0
- yuho/cli/commands/generate.py +316 -0
- yuho/cli/commands/graph.py +410 -0
- yuho/cli/commands/init.py +120 -0
- yuho/cli/commands/library.py +656 -0
- yuho/cli/commands/lint.py +503 -0
- yuho/cli/commands/lsp.py +36 -0
- yuho/cli/commands/preview.py +377 -0
- yuho/cli/commands/repl.py +444 -0
- yuho/cli/commands/serve.py +44 -0
- yuho/cli/commands/test.py +528 -0
- yuho/cli/commands/transpile.py +121 -0
- yuho/cli/commands/wizard.py +370 -0
- yuho/cli/completions.py +182 -0
- yuho/cli/error_formatter.py +193 -0
- yuho/cli/main.py +1064 -0
- yuho/config/__init__.py +46 -0
- yuho/config/loader.py +235 -0
- yuho/config/mask.py +194 -0
- yuho/config/schema.py +147 -0
- yuho/library/__init__.py +84 -0
- yuho/library/index.py +328 -0
- yuho/library/install.py +699 -0
- yuho/library/lockfile.py +330 -0
- yuho/library/package.py +421 -0
- yuho/library/resolver.py +791 -0
- yuho/library/signature.py +335 -0
- yuho/llm/__init__.py +45 -0
- yuho/llm/config.py +75 -0
- yuho/llm/factory.py +123 -0
- yuho/llm/prompts.py +146 -0
- yuho/llm/providers.py +383 -0
- yuho/llm/utils.py +470 -0
- yuho/lsp/__init__.py +14 -0
- yuho/lsp/code_action_handler.py +518 -0
- yuho/lsp/completion_handler.py +85 -0
- yuho/lsp/diagnostics.py +100 -0
- yuho/lsp/hover_handler.py +130 -0
- yuho/lsp/server.py +1425 -0
- yuho/mcp/__init__.py +10 -0
- yuho/mcp/server.py +1452 -0
- yuho/parser/__init__.py +8 -0
- yuho/parser/source_location.py +108 -0
- yuho/parser/wrapper.py +311 -0
- yuho/testing/__init__.py +48 -0
- yuho/testing/coverage.py +274 -0
- yuho/testing/fixtures.py +263 -0
- yuho/transpile/__init__.py +52 -0
- yuho/transpile/alloy_transpiler.py +546 -0
- yuho/transpile/base.py +100 -0
- yuho/transpile/blocks_transpiler.py +338 -0
- yuho/transpile/english_transpiler.py +470 -0
- yuho/transpile/graphql_transpiler.py +404 -0
- yuho/transpile/json_transpiler.py +217 -0
- yuho/transpile/jsonld_transpiler.py +250 -0
- yuho/transpile/latex_preamble.py +161 -0
- yuho/transpile/latex_transpiler.py +406 -0
- yuho/transpile/latex_utils.py +206 -0
- yuho/transpile/mermaid_transpiler.py +357 -0
- yuho/transpile/registry.py +275 -0
- yuho/verify/__init__.py +43 -0
- yuho/verify/alloy.py +352 -0
- yuho/verify/combined.py +218 -0
- yuho/verify/z3_solver.py +1155 -0
- yuho-5.0.0.dist-info/METADATA +186 -0
- yuho-5.0.0.dist-info/RECORD +91 -0
- yuho-5.0.0.dist-info/WHEEL +4 -0
- yuho-5.0.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JSON-LD transpiler with legal ontology context.
|
|
3
|
+
|
|
4
|
+
Extends JSON output with @context, @type, and @id annotations
|
|
5
|
+
following schema.org/Legislation patterns.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
from urllib.parse import quote
|
|
11
|
+
|
|
12
|
+
from yuho.ast import nodes
|
|
13
|
+
from yuho.transpile.base import TranspileTarget, TranspilerBase
|
|
14
|
+
from yuho.transpile.json_transpiler import JSONTranspiler
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# JSON-LD context for legal ontology
|
|
18
|
+
LEGAL_CONTEXT = {
|
|
19
|
+
"@vocab": "https://schema.org/",
|
|
20
|
+
"yuho": "https://yuho.dev/ontology#",
|
|
21
|
+
"eli": "http://data.europa.eu/eli/ontology#",
|
|
22
|
+
|
|
23
|
+
# Schema.org Legislation mappings
|
|
24
|
+
"Statute": "Legislation",
|
|
25
|
+
"section_number": "legislationIdentifier",
|
|
26
|
+
"title": "name",
|
|
27
|
+
"definitions": "yuho:definitions",
|
|
28
|
+
"elements": "yuho:elements",
|
|
29
|
+
"penalty": "yuho:penalty",
|
|
30
|
+
"illustrations": "yuho:illustrations",
|
|
31
|
+
|
|
32
|
+
# Element types
|
|
33
|
+
"ElementNode": "yuho:LegalElement",
|
|
34
|
+
"actus_reus": "yuho:actusReus",
|
|
35
|
+
"mens_rea": "yuho:mensRea",
|
|
36
|
+
"circumstance": "yuho:circumstance",
|
|
37
|
+
|
|
38
|
+
# Penalty mappings
|
|
39
|
+
"PenaltyNode": "yuho:Penalty",
|
|
40
|
+
"imprisonment": "yuho:imprisonment",
|
|
41
|
+
"fine": "yuho:fine",
|
|
42
|
+
"supplementary": "yuho:supplementaryPunishment",
|
|
43
|
+
|
|
44
|
+
# Duration/Money
|
|
45
|
+
"DurationNode": "Duration",
|
|
46
|
+
"MoneyNode": "MonetaryAmount",
|
|
47
|
+
"currency": "currency",
|
|
48
|
+
"amount": "value",
|
|
49
|
+
|
|
50
|
+
# Struct mappings
|
|
51
|
+
"StructDefNode": "yuho:TypeDefinition",
|
|
52
|
+
"StructLiteralNode": "yuho:Instance",
|
|
53
|
+
"FieldDef": "yuho:Field",
|
|
54
|
+
|
|
55
|
+
# Function mappings
|
|
56
|
+
"FunctionDefNode": "yuho:Function",
|
|
57
|
+
|
|
58
|
+
# Match expression
|
|
59
|
+
"MatchExprNode": "yuho:DecisionTree",
|
|
60
|
+
"MatchArm": "yuho:DecisionBranch",
|
|
61
|
+
"pattern": "yuho:condition",
|
|
62
|
+
"body": "yuho:consequence",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class JSONLDTranspiler(TranspilerBase):
|
|
67
|
+
"""
|
|
68
|
+
Transpile Yuho AST to JSON-LD format with legal ontology annotations.
|
|
69
|
+
|
|
70
|
+
Adds @context, @type, and @id to enable linked data queries
|
|
71
|
+
and integration with legal knowledge graphs.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(self, base_uri: str = "https://yuho.dev/statutes/", include_locations: bool = False):
|
|
75
|
+
"""
|
|
76
|
+
Initialize the JSON-LD transpiler.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
base_uri: Base URI for @id generation
|
|
80
|
+
include_locations: Whether to include source locations
|
|
81
|
+
"""
|
|
82
|
+
self.base_uri = base_uri
|
|
83
|
+
self.include_locations = include_locations
|
|
84
|
+
self._json_transpiler = JSONTranspiler(include_locations=include_locations)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def target(self) -> TranspileTarget:
|
|
88
|
+
return TranspileTarget.JSON_LD
|
|
89
|
+
|
|
90
|
+
def transpile(self, ast: nodes.ModuleNode) -> str:
|
|
91
|
+
"""Transpile AST to JSON-LD string."""
|
|
92
|
+
data = self._to_jsonld(ast)
|
|
93
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
94
|
+
|
|
95
|
+
def _to_jsonld(self, node: nodes.ASTNode) -> Dict[str, Any]:
|
|
96
|
+
"""Convert AST node to JSON-LD format."""
|
|
97
|
+
# Start with basic JSON representation
|
|
98
|
+
base = self._json_transpiler._to_dict(node)
|
|
99
|
+
|
|
100
|
+
# Transform to JSON-LD
|
|
101
|
+
result = self._transform_to_jsonld(base, node)
|
|
102
|
+
|
|
103
|
+
# Add context at top level for ModuleNode
|
|
104
|
+
if isinstance(node, nodes.ModuleNode):
|
|
105
|
+
result = {
|
|
106
|
+
"@context": LEGAL_CONTEXT,
|
|
107
|
+
"@graph": result if isinstance(result, list) else [result],
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
def _transform_to_jsonld(self, data: Dict[str, Any], node: nodes.ASTNode) -> Dict[str, Any]:
|
|
113
|
+
"""Transform a JSON dict to JSON-LD format."""
|
|
114
|
+
result = {}
|
|
115
|
+
|
|
116
|
+
# Map _type to @type
|
|
117
|
+
if "_type" in data:
|
|
118
|
+
node_type = data["_type"]
|
|
119
|
+
result["@type"] = self._map_type(node_type)
|
|
120
|
+
|
|
121
|
+
# Generate @id for identifiable nodes
|
|
122
|
+
if isinstance(node, nodes.StatuteNode):
|
|
123
|
+
result["@id"] = f"{self.base_uri}{quote(node.section_number)}"
|
|
124
|
+
elif isinstance(node, nodes.StructDefNode):
|
|
125
|
+
result["@id"] = f"{self.base_uri}types/{quote(node.name)}"
|
|
126
|
+
elif isinstance(node, nodes.FunctionDefNode):
|
|
127
|
+
result["@id"] = f"{self.base_uri}functions/{quote(node.name)}"
|
|
128
|
+
|
|
129
|
+
# Copy and transform remaining fields
|
|
130
|
+
for key, value in data.items():
|
|
131
|
+
if key.startswith("_"):
|
|
132
|
+
continue # Skip internal fields
|
|
133
|
+
|
|
134
|
+
new_key = self._map_property(key)
|
|
135
|
+
|
|
136
|
+
if isinstance(value, dict):
|
|
137
|
+
# Recursively transform nested objects
|
|
138
|
+
child_node = self._get_child_node(node, key)
|
|
139
|
+
result[new_key] = self._transform_to_jsonld(value, child_node) if child_node else value
|
|
140
|
+
elif isinstance(value, list):
|
|
141
|
+
# Transform list items
|
|
142
|
+
result[new_key] = [
|
|
143
|
+
self._transform_to_jsonld(item, self._get_list_item_node(node, key, i))
|
|
144
|
+
if isinstance(item, dict) else item
|
|
145
|
+
for i, item in enumerate(value)
|
|
146
|
+
]
|
|
147
|
+
else:
|
|
148
|
+
result[new_key] = value
|
|
149
|
+
|
|
150
|
+
return result
|
|
151
|
+
|
|
152
|
+
def _map_type(self, node_type: str) -> str:
|
|
153
|
+
"""Map internal type name to JSON-LD type."""
|
|
154
|
+
type_mapping = {
|
|
155
|
+
"ModuleNode": "yuho:Module",
|
|
156
|
+
"StatuteNode": "Legislation",
|
|
157
|
+
"StructDefNode": "yuho:TypeDefinition",
|
|
158
|
+
"StructLiteralNode": "yuho:Instance",
|
|
159
|
+
"FunctionDefNode": "yuho:Function",
|
|
160
|
+
"MatchExprNode": "yuho:DecisionTree",
|
|
161
|
+
"MatchArm": "yuho:DecisionBranch",
|
|
162
|
+
"ElementNode": "yuho:LegalElement",
|
|
163
|
+
"PenaltyNode": "yuho:Penalty",
|
|
164
|
+
"DurationNode": "Duration",
|
|
165
|
+
"MoneyNode": "MonetaryAmount",
|
|
166
|
+
"StringLit": "Text",
|
|
167
|
+
"IntLit": "Integer",
|
|
168
|
+
"FloatLit": "Number",
|
|
169
|
+
"BoolLit": "Boolean",
|
|
170
|
+
"DateNode": "Date",
|
|
171
|
+
"PercentNode": "yuho:Percentage",
|
|
172
|
+
"ImportNode": "yuho:Import",
|
|
173
|
+
"IllustrationNode": "yuho:Illustration",
|
|
174
|
+
"DefinitionEntry": "DefinedTerm",
|
|
175
|
+
}
|
|
176
|
+
return type_mapping.get(node_type, f"yuho:{node_type}")
|
|
177
|
+
|
|
178
|
+
def _map_property(self, prop: str) -> str:
|
|
179
|
+
"""Map internal property name to JSON-LD property."""
|
|
180
|
+
prop_mapping = {
|
|
181
|
+
"section_number": "legislationIdentifier",
|
|
182
|
+
"title": "name",
|
|
183
|
+
"definitions": "yuho:hasDefinition",
|
|
184
|
+
"elements": "yuho:hasElement",
|
|
185
|
+
"penalty": "yuho:hasPenalty",
|
|
186
|
+
"illustrations": "yuho:hasIllustration",
|
|
187
|
+
"element_type": "yuho:elementType",
|
|
188
|
+
"description": "description",
|
|
189
|
+
"term": "name",
|
|
190
|
+
"definition": "description",
|
|
191
|
+
"imprisonment_min": "yuho:minImprisonment",
|
|
192
|
+
"imprisonment_max": "yuho:maxImprisonment",
|
|
193
|
+
"fine_min": "yuho:minFine",
|
|
194
|
+
"fine_max": "yuho:maxFine",
|
|
195
|
+
"supplementary": "yuho:supplementaryPunishment",
|
|
196
|
+
"scrutinee": "yuho:subject",
|
|
197
|
+
"arms": "yuho:hasBranch",
|
|
198
|
+
"pattern": "yuho:condition",
|
|
199
|
+
"guard": "yuho:guard",
|
|
200
|
+
"body": "yuho:consequence",
|
|
201
|
+
"struct_name": "yuho:instanceOf",
|
|
202
|
+
"fields": "yuho:hasField",
|
|
203
|
+
"field_values": "yuho:hasFieldValue",
|
|
204
|
+
"type_defs": "yuho:definesType",
|
|
205
|
+
"function_defs": "yuho:definesFunction",
|
|
206
|
+
"statutes": "yuho:containsLegislation",
|
|
207
|
+
"imports": "yuho:imports",
|
|
208
|
+
"variables": "yuho:definesVariable",
|
|
209
|
+
"params": "yuho:hasParameter",
|
|
210
|
+
"return_type": "yuho:returnType",
|
|
211
|
+
"type": "yuho:type",
|
|
212
|
+
"value": "yuho:value",
|
|
213
|
+
"name": "name",
|
|
214
|
+
"callee": "yuho:callee",
|
|
215
|
+
"args": "yuho:arguments",
|
|
216
|
+
"operator": "yuho:operator",
|
|
217
|
+
"left": "yuho:leftOperand",
|
|
218
|
+
"right": "yuho:rightOperand",
|
|
219
|
+
"operand": "yuho:operand",
|
|
220
|
+
"base": "yuho:base",
|
|
221
|
+
"field_name": "yuho:fieldName",
|
|
222
|
+
"index": "yuho:index",
|
|
223
|
+
"currency": "priceCurrency",
|
|
224
|
+
"amount": "value",
|
|
225
|
+
"years": "yuho:years",
|
|
226
|
+
"months": "yuho:months",
|
|
227
|
+
"days": "yuho:days",
|
|
228
|
+
"hours": "yuho:hours",
|
|
229
|
+
"minutes": "yuho:minutes",
|
|
230
|
+
"seconds": "yuho:seconds",
|
|
231
|
+
}
|
|
232
|
+
return prop_mapping.get(prop, prop)
|
|
233
|
+
|
|
234
|
+
def _get_child_node(self, parent: nodes.ASTNode, field: str) -> Optional[nodes.ASTNode]:
|
|
235
|
+
"""Get child node for a field."""
|
|
236
|
+
if hasattr(parent, field):
|
|
237
|
+
child = getattr(parent, field)
|
|
238
|
+
if isinstance(child, nodes.ASTNode):
|
|
239
|
+
return child
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
def _get_list_item_node(self, parent: nodes.ASTNode, field: str, index: int) -> Optional[nodes.ASTNode]:
|
|
243
|
+
"""Get node for list item at index."""
|
|
244
|
+
if hasattr(parent, field):
|
|
245
|
+
children = getattr(parent, field)
|
|
246
|
+
if isinstance(children, (list, tuple)) and index < len(children):
|
|
247
|
+
item = children[index]
|
|
248
|
+
if isinstance(item, nodes.ASTNode):
|
|
249
|
+
return item
|
|
250
|
+
return None
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LaTeX preamble generation for legal documents.
|
|
3
|
+
|
|
4
|
+
Contains all the LaTeX document setup including:
|
|
5
|
+
- Document class and packages
|
|
6
|
+
- Custom commands and environments
|
|
7
|
+
- Style definitions for legal documents
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import List
|
|
11
|
+
|
|
12
|
+
from yuho.transpile.latex_utils import escape_latex
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def generate_preamble(
|
|
16
|
+
document_title: str = "Legal Statutes",
|
|
17
|
+
author: str = "",
|
|
18
|
+
use_margins: bool = True,
|
|
19
|
+
) -> List[str]:
|
|
20
|
+
"""
|
|
21
|
+
Generate LaTeX preamble for legal documents.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
document_title: Title for the document
|
|
25
|
+
author: Document author
|
|
26
|
+
use_margins: Whether to use margin notes
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
List of preamble lines
|
|
30
|
+
"""
|
|
31
|
+
lines: List[str] = []
|
|
32
|
+
|
|
33
|
+
def emit(text: str) -> None:
|
|
34
|
+
lines.append(text)
|
|
35
|
+
|
|
36
|
+
def emit_blank() -> None:
|
|
37
|
+
lines.append("")
|
|
38
|
+
|
|
39
|
+
# Document class
|
|
40
|
+
emit(r"\documentclass[11pt,a4paper]{article}")
|
|
41
|
+
emit_blank()
|
|
42
|
+
|
|
43
|
+
# Essential packages
|
|
44
|
+
emit(r"% Essential packages")
|
|
45
|
+
emit(r"\usepackage[utf8]{inputenc}")
|
|
46
|
+
emit(r"\usepackage[T1]{fontenc}")
|
|
47
|
+
emit(r"\usepackage{lmodern}")
|
|
48
|
+
emit_blank()
|
|
49
|
+
|
|
50
|
+
# Page geometry
|
|
51
|
+
emit(r"% Page layout")
|
|
52
|
+
if use_margins:
|
|
53
|
+
emit(r"\usepackage[a4paper,left=3cm,right=4cm,top=2.5cm,bottom=2.5cm,marginparwidth=3cm]{geometry}")
|
|
54
|
+
else:
|
|
55
|
+
emit(r"\usepackage[a4paper,margin=2.5cm]{geometry}")
|
|
56
|
+
emit_blank()
|
|
57
|
+
|
|
58
|
+
# Typography
|
|
59
|
+
emit(r"% Typography")
|
|
60
|
+
emit(r"\usepackage{microtype}")
|
|
61
|
+
emit(r"\usepackage{parskip}")
|
|
62
|
+
emit(r"\setlength{\parindent}{0pt}")
|
|
63
|
+
emit_blank()
|
|
64
|
+
|
|
65
|
+
# Colors and boxes
|
|
66
|
+
emit(r"% Colors and boxes for illustrations")
|
|
67
|
+
emit(r"\usepackage{xcolor}")
|
|
68
|
+
emit(r"\usepackage{tcolorbox}")
|
|
69
|
+
emit(r"\tcbuselibrary{skins}")
|
|
70
|
+
emit_blank()
|
|
71
|
+
|
|
72
|
+
# Define illustration box style
|
|
73
|
+
emit(r"% Illustration box style")
|
|
74
|
+
emit(r"\newtcolorbox{illustrationbox}[1][]{")
|
|
75
|
+
emit(r" enhanced,")
|
|
76
|
+
emit(r" colback=gray!10,")
|
|
77
|
+
emit(r" colframe=gray!50,")
|
|
78
|
+
emit(r" fontupper=\itshape,")
|
|
79
|
+
emit(r" boxrule=0.5pt,")
|
|
80
|
+
emit(r" left=10pt,")
|
|
81
|
+
emit(r" right=10pt,")
|
|
82
|
+
emit(r" top=8pt,")
|
|
83
|
+
emit(r" bottom=8pt,")
|
|
84
|
+
emit(r" #1")
|
|
85
|
+
emit(r"}")
|
|
86
|
+
emit_blank()
|
|
87
|
+
|
|
88
|
+
# Tables
|
|
89
|
+
emit(r"% Tables for penalties")
|
|
90
|
+
emit(r"\usepackage{booktabs}")
|
|
91
|
+
emit(r"\usepackage{array}")
|
|
92
|
+
emit(r"\usepackage{longtable}")
|
|
93
|
+
emit_blank()
|
|
94
|
+
|
|
95
|
+
# Margin notes
|
|
96
|
+
if use_margins:
|
|
97
|
+
emit(r"% Margin notes")
|
|
98
|
+
emit(r"\usepackage{marginnote}")
|
|
99
|
+
emit(r"\renewcommand*{\marginfont}{\footnotesize\sffamily}")
|
|
100
|
+
emit_blank()
|
|
101
|
+
|
|
102
|
+
# Hyperlinks and cross-references
|
|
103
|
+
emit(r"% Hyperlinks")
|
|
104
|
+
emit(r"\usepackage{hyperref}")
|
|
105
|
+
emit(r"\hypersetup{")
|
|
106
|
+
emit(r" colorlinks=true,")
|
|
107
|
+
emit(r" linkcolor=blue!60!black,")
|
|
108
|
+
emit(r" urlcolor=blue!60!black,")
|
|
109
|
+
emit(r" pdftitle={" + escape_latex(document_title) + "},")
|
|
110
|
+
if author:
|
|
111
|
+
emit(r" pdfauthor={" + escape_latex(author) + "},")
|
|
112
|
+
emit(r"}")
|
|
113
|
+
emit_blank()
|
|
114
|
+
|
|
115
|
+
# Section formatting for statutes
|
|
116
|
+
emit(r"% Statute section formatting")
|
|
117
|
+
emit(r"\usepackage{titlesec}")
|
|
118
|
+
emit(r"\titleformat{\section}")
|
|
119
|
+
emit(r" {\normalfont\Large\bfseries}")
|
|
120
|
+
emit(r" {Section \thesection}")
|
|
121
|
+
emit(r" {1em}")
|
|
122
|
+
emit(r" {}")
|
|
123
|
+
emit_blank()
|
|
124
|
+
|
|
125
|
+
# Custom commands for legal formatting
|
|
126
|
+
emit(r"% Custom commands for legal formatting")
|
|
127
|
+
emit(r"\newcommand{\statute}[2]{%")
|
|
128
|
+
emit(r" \subsection[Section #1 --- #2]{Section #1 --- #2}%")
|
|
129
|
+
emit(r" \label{sec:#1}%")
|
|
130
|
+
emit(r"}")
|
|
131
|
+
emit_blank()
|
|
132
|
+
|
|
133
|
+
emit(r"\newcommand{\sectionref}[1]{Section~\ref{sec:#1}}")
|
|
134
|
+
emit_blank()
|
|
135
|
+
|
|
136
|
+
emit(r"\newcommand{\element}[2]{%")
|
|
137
|
+
emit(r" \textbf{#1:} #2%")
|
|
138
|
+
emit(r"}")
|
|
139
|
+
emit_blank()
|
|
140
|
+
|
|
141
|
+
# Definition list environment
|
|
142
|
+
emit(r"% Definition list for legal definitions")
|
|
143
|
+
emit(r"\newenvironment{legaldefs}{%")
|
|
144
|
+
emit(r" \begin{description}[leftmargin=2em,style=nextline]")
|
|
145
|
+
emit(r"}{%")
|
|
146
|
+
emit(r" \end{description}")
|
|
147
|
+
emit(r"}")
|
|
148
|
+
emit(r"\usepackage{enumitem}")
|
|
149
|
+
emit_blank()
|
|
150
|
+
|
|
151
|
+
# Document metadata
|
|
152
|
+
emit(r"% Document metadata")
|
|
153
|
+
emit(r"\title{" + escape_latex(document_title) + "}")
|
|
154
|
+
if author:
|
|
155
|
+
emit(r"\author{" + escape_latex(author) + "}")
|
|
156
|
+
else:
|
|
157
|
+
emit(r"\author{}")
|
|
158
|
+
emit(r"\date{\today}")
|
|
159
|
+
emit_blank()
|
|
160
|
+
|
|
161
|
+
return lines
|