ssc_codegen 0.13.4__tar.gz → 0.15.0__tar.gz

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.

Potentially problematic release.


This version of ssc_codegen might be problematic. Click here for more details.

Files changed (64) hide show
  1. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/PKG-INFO +11 -11
  2. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/README.md +10 -10
  3. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/pyproject.toml +1 -1
  4. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/__init__.py +4 -3
  5. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/__init__.py +4 -1
  6. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_core.py +41 -3
  7. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_build/builder.py +39 -1
  8. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/code_callbacks.py +0 -2
  9. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/main.py +0 -2
  10. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/go_goquery.py +31 -12
  11. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/js_pure.py +32 -3
  12. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/lua_htmlparser.py +32 -1
  13. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/py_base.py +59 -31
  14. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/py_bs4.py +30 -2
  15. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/py_lxml.py +38 -27
  16. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/py_parsel.py +30 -2
  17. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/py_selectolax.py +29 -1
  18. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/py_base.py +12 -5
  19. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/document.py +34 -1
  20. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/schema.py +15 -1
  21. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/tokens.py +6 -0
  22. ssc_codegen-0.15.0/ssc_codegen/transform.py +95 -0
  23. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/.gitignore +0 -0
  24. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/LICENSE +0 -0
  25. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/_compat.py +0 -0
  26. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/base.py +0 -0
  27. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_array.py +0 -0
  28. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_cast.py +0 -0
  29. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_filter.py +0 -0
  30. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_selectors.py +0 -0
  31. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_string.py +0 -0
  32. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_/nodes_validate.py +0 -0
  33. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_build/__init__.py +0 -0
  34. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_build/main.py +0 -0
  35. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_build/utils.py +0 -0
  36. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_grep_rules/js_rules.yml +0 -0
  37. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_grep_rules/py_drop_prefix_suffix_backport.yml +0 -0
  38. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/ast_grep_rules/py_rules.yml +0 -0
  39. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/__init__.py +0 -0
  40. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/ast_grep.py +0 -0
  41. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/cli_callbacks.py +0 -0
  42. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/cli_utils.py +0 -0
  43. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/consts.py +0 -0
  44. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/cli/runtime_parse_runners.py +0 -0
  45. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/compiler.py +0 -0
  46. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/__init__.py +0 -0
  47. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/base.py +0 -0
  48. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/helpers.py +0 -0
  49. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/__init__.py +0 -0
  50. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/go_goquery.py +0 -0
  51. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/js_pure.py +0 -0
  52. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/lua_base.py +0 -0
  53. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/lua_css_compat.py +0 -0
  54. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/converters/templates/lua_re_compat.py +0 -0
  55. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/document_utlis.py +0 -0
  56. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/json_struct.py +0 -0
  57. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/json_to_scc.py +0 -0
  58. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/logs.py +0 -0
  59. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/pseudo_selectors.py +0 -0
  60. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/selector_utils.py +0 -0
  61. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/static_checker/__init__.py +0 -0
  62. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/static_checker/base.py +0 -0
  63. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/static_checker/callbacks.py +0 -0
  64. {ssc_codegen-0.13.4 → ssc_codegen-0.15.0}/ssc_codegen/str_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssc_codegen
3
- Version: 0.13.4
3
+ Version: 0.15.0
4
4
  Summary: Python-dsl code converter to html parser for web scraping
5
5
  Project-URL: Documentation, https://github.com/vypivshiy/selector_schema_codegen#readme
6
6
  Project-URL: Issues, https://github.com/vypivshiy/selector_schema_codegen/issues
@@ -58,15 +58,15 @@ ssc-gen - a python-based DSL to describe parsers for html documents, which is tr
58
58
 
59
59
  Current support converters
60
60
 
61
- | Language | HTML parser lib + dependencies | XPath | CSS3 | CSS4 | Generated annotations, types, structs | formatter dependency |
62
- | ---------------------------------------- | -------------------------------------- | ----- | ---- | ---- | ------------------------------------- | -------------------- |
63
- | Python (3.8+) | bs4, lxml | N | Y | Y | TypedDict`1`, list, dict | ruff |
64
- | ... | parsel | Y | Y | N | ... | ... |
65
- | ... | selectolax (lexbor) | N | Y | N | ... | ... |
66
- | ... | lxml | Y | Y | N | ... | ... |
67
- | js (ES6)`2` | pure (firefox/chrome extension/nodejs) | Y | Y | Y | JSDoc | prettier |
68
- | go (1.10+) **(UNSTABLE)** | goquery, gjson (`4`) | N | Y | N | struct(+json anchors), array, map | gofmt |
69
- | lua (5.2+), luajit(2+) **(UNSTABLE)**`5` | lua-htmlparser, lrexlib(opt), dkjson | N | Y | N | EmmyLua | LuaFormatter |
61
+ | Language | HTML parser lib + dependencies | XPath | CSS3 | CSS4 | Generated annotations, types, structs | formatter dependency |
62
+ | ---------------------------------------- | ------------------------------------------------------ | ----- | ---- | ---- | ------------------------------------- | -------------------- |
63
+ | Python (3.8-3.13) | bs4, lxml ( typing_extensions if py < 3.10 ) | N | Y | Y | TypedDict`1`, list, dict | ruff |
64
+ | ... | parsel ( typing_extensions if py < 3.10 ) | Y | Y | N | ... | ... |
65
+ | ... | selectolax (lexbor) ( typing_extensions if py < 3.10 ) | N | Y | N | ... | ... |
66
+ | ... | lxml ( typing_extensions if py < 3.10 ) | Y | Y | N | ... | ... |
67
+ | js (ES6)`2` | pure (firefox/chrome extension/nodejs) | Y | Y | Y | JSDoc | prettier |
68
+ | go (1.10+) **(UNSTABLE)** | goquery, gjson (`4`) | N | Y | N | struct(+json anchors), array, map | gofmt |
69
+ | lua (5.2+), luajit(2+) **(UNSTABLE)**`5` | lua-htmlparser, lrexlib(opt), dkjson | N | Y | N | EmmyLua | LuaFormatter |
70
70
 
71
71
  - **CSS3** means support next selectors:
72
72
  - basic: (`tag`, `.class`, `#id`, `tag1,tag2`)
@@ -99,6 +99,7 @@ For maximum portability of the configuration to the target language:
99
99
  Check the html parser lib documentation aboud CSS selectors before implement code. Examples:
100
100
  1. Several libs not support `+` operations (eg: [selectolax(modest)](https://github.com/rushter/selectolax), [dart.universal_html](https://pub.dev/packages/universal_html))
101
101
  2. For research purpose, lua_htmlparser include converter for unsupported CSS3 query syntax
102
+
102
103
  2. HTML parser libs maybe not supports attribute selectors: `*=`, `~=`, `|=`, `^=`, `$=`
103
104
  3. Several libs not support pseudo classes (eg: standard [dart.html](https://dart.dev/libraries/dart-html) lib miss this feature).
104
105
 
@@ -245,7 +246,6 @@ You can use any html source:
245
246
 
246
247
  ## See also
247
248
 
248
-
249
249
  - [Brief](docs/briefing.md) about css selectors and regular expressions
250
250
  - [Explain](docs/explain.md) short document on how to understand DSL syntax
251
251
  - [LLM](llm.md) experimental prompt for generate code
@@ -23,15 +23,15 @@ ssc-gen - a python-based DSL to describe parsers for html documents, which is tr
23
23
 
24
24
  Current support converters
25
25
 
26
- | Language | HTML parser lib + dependencies | XPath | CSS3 | CSS4 | Generated annotations, types, structs | formatter dependency |
27
- | ---------------------------------------- | -------------------------------------- | ----- | ---- | ---- | ------------------------------------- | -------------------- |
28
- | Python (3.8+) | bs4, lxml | N | Y | Y | TypedDict`1`, list, dict | ruff |
29
- | ... | parsel | Y | Y | N | ... | ... |
30
- | ... | selectolax (lexbor) | N | Y | N | ... | ... |
31
- | ... | lxml | Y | Y | N | ... | ... |
32
- | js (ES6)`2` | pure (firefox/chrome extension/nodejs) | Y | Y | Y | JSDoc | prettier |
33
- | go (1.10+) **(UNSTABLE)** | goquery, gjson (`4`) | N | Y | N | struct(+json anchors), array, map | gofmt |
34
- | lua (5.2+), luajit(2+) **(UNSTABLE)**`5` | lua-htmlparser, lrexlib(opt), dkjson | N | Y | N | EmmyLua | LuaFormatter |
26
+ | Language | HTML parser lib + dependencies | XPath | CSS3 | CSS4 | Generated annotations, types, structs | formatter dependency |
27
+ | ---------------------------------------- | ------------------------------------------------------ | ----- | ---- | ---- | ------------------------------------- | -------------------- |
28
+ | Python (3.8-3.13) | bs4, lxml ( typing_extensions if py < 3.10 ) | N | Y | Y | TypedDict`1`, list, dict | ruff |
29
+ | ... | parsel ( typing_extensions if py < 3.10 ) | Y | Y | N | ... | ... |
30
+ | ... | selectolax (lexbor) ( typing_extensions if py < 3.10 ) | N | Y | N | ... | ... |
31
+ | ... | lxml ( typing_extensions if py < 3.10 ) | Y | Y | N | ... | ... |
32
+ | js (ES6)`2` | pure (firefox/chrome extension/nodejs) | Y | Y | Y | JSDoc | prettier |
33
+ | go (1.10+) **(UNSTABLE)** | goquery, gjson (`4`) | N | Y | N | struct(+json anchors), array, map | gofmt |
34
+ | lua (5.2+), luajit(2+) **(UNSTABLE)**`5` | lua-htmlparser, lrexlib(opt), dkjson | N | Y | N | EmmyLua | LuaFormatter |
35
35
 
36
36
  - **CSS3** means support next selectors:
37
37
  - basic: (`tag`, `.class`, `#id`, `tag1,tag2`)
@@ -64,6 +64,7 @@ For maximum portability of the configuration to the target language:
64
64
  Check the html parser lib documentation aboud CSS selectors before implement code. Examples:
65
65
  1. Several libs not support `+` operations (eg: [selectolax(modest)](https://github.com/rushter/selectolax), [dart.universal_html](https://pub.dev/packages/universal_html))
66
66
  2. For research purpose, lua_htmlparser include converter for unsupported CSS3 query syntax
67
+
67
68
  2. HTML parser libs maybe not supports attribute selectors: `*=`, `~=`, `|=`, `^=`, `$=`
68
69
  3. Several libs not support pseudo classes (eg: standard [dart.html](https://dart.dev/libraries/dart-html) lib miss this feature).
69
70
 
@@ -210,7 +211,6 @@ You can use any html source:
210
211
 
211
212
  ## See also
212
213
 
213
-
214
214
  - [Brief](docs/briefing.md) about css selectors and regular expressions
215
215
  - [Explain](docs/explain.md) short document on how to understand DSL syntax
216
216
  - [LLM](llm.md) experimental prompt for generate code
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssc_codegen"
3
- version = "0.13.4"
3
+ version = "0.15.0"
4
4
  description = "Python-dsl code converter to html parser for web scraping "
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,13 +1,13 @@
1
1
  from ssc_codegen.document import DocumentElementsFilter, HTMLDocument, ClassVarDocument, StringDocument, ArrayDocument, AssertDocument, NestedDocument, \
2
2
  DefaultDocument, \
3
- NumericDocument, JsonDocument, BooleanDocument, DocumentFilter
3
+ NumericDocument, JsonDocument, BooleanDocument, DocumentFilter, TransformDocument
4
4
  from ssc_codegen.json_struct import Json
5
5
  from ssc_codegen.logs import setup_logger
6
6
  from ssc_codegen.schema import ItemSchema, DictSchema, ListSchema, FlatListSchema, AccUniqueListSchema
7
7
 
8
8
  setup_logger()
9
9
 
10
- VERSION = "0.13.4"
10
+ VERSION = "0.15.0"
11
11
 
12
12
 
13
13
  class __MISSING(object):
@@ -26,7 +26,8 @@ class Document(
26
26
  DefaultDocument,
27
27
  NumericDocument,
28
28
  JsonDocument,
29
- BooleanDocument
29
+ BooleanDocument,
30
+ TransformDocument
30
31
  ):
31
32
  """Special Common Document or Element marker manipulations"""
32
33
  pass
@@ -38,7 +38,10 @@ from .nodes_core import (
38
38
  ExprClassVar,
39
39
  ExprCallStructClassVar,
40
40
  CodeStart,
41
- CodeEnd
41
+ CodeEnd,
42
+ ExprTransform,
43
+ ModuleTransformImports,
44
+ ModuleUtilities
42
45
  )
43
46
  from .nodes_filter import (
44
47
  FilterOr,
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Sequence, TypedDict, ClassVar, TypeVar
2
+ from typing import Sequence, TypedDict, ClassVar, TypeVar, TYPE_CHECKING
3
3
 
4
4
  from ssc_codegen.ast_.base import T_EMPTY_KWARGS, BaseAstNode
5
5
  from ssc_codegen.ast_.base import (
@@ -14,6 +14,9 @@ from ssc_codegen.tokens import (
14
14
  VariableType,
15
15
  )
16
16
 
17
+ if TYPE_CHECKING:
18
+ from ssc_codegen.transform import BaseTransform
19
+
17
20
  KW_DOCSTRING = TypedDict("KW_DOCSTRING", {"value": str})
18
21
 
19
22
 
@@ -34,11 +37,32 @@ class Docstring(_DisableRepr, BaseAstNode[KW_DOCSTRING, tuple[str]]):
34
37
  """
35
38
 
36
39
  kind: ClassVar[TokenType] = TokenType.DOCSTRING
37
- kwargs: KW_DOCSTRING
40
+
41
+
42
+ # push transform for resolve imports (dependencies)
43
+ KW_MODULE_IMPORTS = TypedDict(
44
+ "KW_MODULE_IMPORTS", {"transforms": list["BaseTransform"]}
45
+ )
46
+ ARGS_MODULE_IMPORTS = tuple[list["BaseTransform"]]
47
+
48
+
49
+ @dataclass(kw_only=True)
50
+ class ModuleTransformImports(
51
+ BaseAstNode[KW_MODULE_IMPORTS, ARGS_MODULE_IMPORTS]
52
+ ):
53
+ """AST node representing module import transfrom dependencies.
54
+
55
+ This node contains import statements that will be added to the
56
+ generated module to ensure required dependencies are available.
57
+ """
58
+
59
+ kind: ClassVar[TokenType] = TokenType.TRANSFORM_IMPORTS
38
60
 
39
61
 
40
62
  @dataclass(kw_only=True)
41
- class ModuleImports(_DisableRepr, BaseAstNode[T_EMPTY_KWARGS, tuple]):
63
+ class ModuleImports(
64
+ _DisableRepr, BaseAstNode[KW_MODULE_IMPORTS, ARGS_MODULE_IMPORTS]
65
+ ):
42
66
  """AST node representing module import statements.
43
67
 
44
68
  This node contains import statements that will be added to the
@@ -551,3 +575,17 @@ class CodeEnd(_DisableRepr, BaseAstNode):
551
575
  """
552
576
 
553
577
  kind: ClassVar[TokenType] = TokenType.CODE_END
578
+
579
+
580
+ KW_TRANSFORM = TypedDict("KW_TRANSFORM", {"transform": "BaseTransform"})
581
+ ARGS_TRANSFORM = tuple["BaseTransform"]
582
+
583
+
584
+ @dataclass(kw_only=True)
585
+ class ExprTransform(BaseAstNode[KW_TRANSFORM, ARGS_TRANSFORM]):
586
+ kind: ClassVar[TokenType] = TokenType.TRANSFORM
587
+
588
+
589
+ @dataclass(kw_only=True)
590
+ class ModuleUtilities(_DisableRepr, BaseAstNode):
591
+ kind: ClassVar[TokenType] = TokenType.UTILITIES
@@ -3,6 +3,7 @@ from typing import MutableSequence, Type, cast
3
3
  import warnings
4
4
  from typing_extensions import Self
5
5
 
6
+ from ssc_codegen.ast_ import ModuleTransformImports, ModuleUtilities
6
7
  from ssc_codegen.ast_.base import BaseAstNode
7
8
  from ssc_codegen.ast_.nodes_cast import ExprJsonify, ExprNested
8
9
  from ssc_codegen.ast_.nodes_core import (
@@ -113,7 +114,16 @@ class AstBuilder:
113
114
  Docstring(kwargs={"value": module_doc}, parent=self.module)
114
115
  )
115
116
  # import node
116
- self.module.body.append(ModuleImports(parent=self.module))
117
+ # fallback add ModuleImports.kwargs["transform"] if target language not allowed use multiple import directives
118
+ self.module.body.append(
119
+ ModuleImports(parent=self.module, kwargs={"transforms": []})
120
+ )
121
+ self.module.body.append(
122
+ ModuleTransformImports(
123
+ parent=self.module, kwargs={"transforms": []}
124
+ )
125
+ )
126
+ self.module.body.append(ModuleUtilities(parent=self.module))
117
127
  # CodeStart hook node
118
128
  self.module.body.append(CodeStart(parent=self.module))
119
129
  return self
@@ -398,10 +408,23 @@ class AstBuilder:
398
408
  # generate typedef as annotation node
399
409
  return st
400
410
 
411
+ @staticmethod
412
+ def is_collected_type_transform(transforms: list, target: object) -> bool:
413
+ for t in transforms:
414
+ if isinstance(t, type(target)):
415
+ return True
416
+ return False
417
+
401
418
  def add_struct_parsers(self, *struct_parsers: Type[BaseSchema]) -> Self:
402
419
  ssc_structs = []
403
420
  ssc_typedefs = []
421
+ ssc_transforms = []
404
422
  for schema in struct_parsers:
423
+ if schema.__SSC_TRANSFORMS__:
424
+ # check current used transforms for avoid generate duplicate imports
425
+ for t in schema.__SSC_TRANSFORMS__:
426
+ if not any(isinstance(i, type(t)) for i in ssc_transforms):
427
+ ssc_transforms.append(t)
405
428
  if is_literals_only_schema(schema):
406
429
  if schema.__SCHEMA_TYPE__ != StructType.ITEM:
407
430
  raise TypeError(
@@ -420,6 +443,21 @@ class AstBuilder:
420
443
  continue
421
444
  ssc_typedefs.append(typedef)
422
445
  # assembly
446
+
447
+ # insert transforms imports (in high-level API provide insert dependencies)
448
+
449
+ node_transform_import = self.module.find_node_by_token(
450
+ ModuleTransformImports.kind
451
+ )
452
+ node_transform_import = cast(
453
+ ModuleTransformImports, node_transform_import
454
+ )
455
+ node_transform_import.kwargs["transforms"] = ssc_transforms.copy()
456
+
457
+ node_import = self.module.find_node_by_token(ModuleImports.kind)
458
+ node_import = cast(ModuleImports, node_import)
459
+ node_import.kwargs["transform"] = ssc_transforms.copy()
460
+
423
461
  self.module.body.extend(ssc_typedefs)
424
462
  self.module.body.extend(ssc_structs)
425
463
  self.module.body.append(CodeEnd(parent=self.module))
@@ -3,7 +3,6 @@
3
3
  from typing import Callable
4
4
  from ssc_codegen.str_utils import (
5
5
  go_unimport_naive,
6
- py_remove_unused_none_type_import,
7
6
  )
8
7
 
9
8
 
@@ -28,7 +27,6 @@ class BaseCodeCallback:
28
27
  return code
29
28
 
30
29
 
31
- CB_PY_CODE = BaseCodeCallback(py_remove_unused_none_type_import)
32
30
  CB_GO_CODE = BaseCodeCallback(go_unimport_naive, remove_empty_lines=True)
33
31
  CB_DART_CODE = BaseCodeCallback(remove_empty_lines=True)
34
32
  CB_JS_CODE = BaseCodeCallback(remove_empty_lines=True)
@@ -25,7 +25,6 @@ from ssc_codegen.cli.cli_utils import (
25
25
  suggest_class_name,
26
26
  )
27
27
  from ssc_codegen.cli.code_callbacks import (
28
- CB_PY_CODE,
29
28
  CB_GO_CODE,
30
29
  CB_JS_CODE,
31
30
  )
@@ -208,7 +207,6 @@ def gen_py(
208
207
  xpath_to_css=to_css,
209
208
  css_to_xpath=to_xpath,
210
209
  debug_instructions=debug,
211
- code_cb=CB_PY_CODE,
212
210
  gen_docstring=docstring,
213
211
  )
214
212
 
@@ -51,6 +51,9 @@ from typing_extensions import assert_never
51
51
 
52
52
  from ssc_codegen.ast_ import (
53
53
  Docstring,
54
+ ExprTransform,
55
+ ModuleTransformImports,
56
+ ModuleUtilities,
54
57
  StructParser,
55
58
  ExprReturn,
56
59
  ExprNoReturn,
@@ -393,21 +396,37 @@ def pre_docstring(node: Docstring) -> str:
393
396
 
394
397
  @CONVERTER(ModuleImports.kind)
395
398
  def pre_module_imports(_node: ModuleImports) -> str:
399
+ # TODO: resolve imports
400
+ return IMPORTS.replace("$PACKAGE$", CONVERTER.PACKAGE)
401
+
402
+
403
+ @CONVERTER(ModuleTransformImports.kind)
404
+ def pre_transform_imports(node: ModuleTransformImports) -> str:
405
+ transforms, *_ = node.unpack_args()
406
+ if transforms:
407
+ for t in transforms:
408
+ if t.collect_dependencies("go_goquery"):
409
+ raise NotImplementedError(
410
+ "Current converter implementation not support pass extra import dependencies"
411
+ )
412
+ return ""
413
+
414
+
415
+ @CONVERTER(ExprTransform.kind)
416
+ def pre_transform(node: ExprTransform) -> str:
417
+ prv, nxt = prev_next_var(node)
418
+ transform, *_ = node.unpack_args()
419
+ parts = transform.emit("go_goquery", prv, nxt)
420
+ return "\n" + "\n".join(parts)
421
+
422
+
423
+ @CONVERTER(ModuleUtilities.kind)
424
+ def pre_module_utilities(_: ModuleUtilities) -> str:
396
425
  # HACK:
397
- # golang not allowed override functions, check loaded helper functions by flag
398
- helper_functions = (
399
- HELPER_FUNCTIONS if not CONVERTER.HELPER_FUNCS_IMPORTED else ""
400
- )
401
- code = (
402
- # magic constant
403
- IMPORTS.replace("$PACKAGE$", CONVERTER.PACKAGE)
404
- # HACK: push helper functions to ModuleImports token:
405
- # its generated second after module docstring
406
- + helper_functions
407
- )
426
+ # golang not allowed override or duplicate functions, check loaded helper functions by flag
408
427
  if not CONVERTER.HELPER_FUNCS_IMPORTED:
409
428
  CONVERTER.HELPER_FUNCS_IMPORTED = True
410
- return code
429
+ return HELPER_FUNCTIONS if not CONVERTER.HELPER_FUNCS_IMPORTED else ""
411
430
 
412
431
 
413
432
  def get_typedef_field_by_name(node: TypeDef, field_name: str) -> str:
@@ -23,6 +23,9 @@ from typing import cast
23
23
 
24
24
  from ssc_codegen.ast_ import (
25
25
  Docstring,
26
+ ExprTransform,
27
+ ModuleTransformImports,
28
+ ModuleUtilities,
26
29
  StructParser,
27
30
  ExprReturn,
28
31
  ExprNoReturn,
@@ -173,7 +176,11 @@ DOCSTR_START = "/**"
173
176
  DOCSTR_END = "*/"
174
177
  DOCSTR_SEP = "* "
175
178
  CONVERTER = BaseCodeConverter(debug_comment_prefix="// ")
176
- # javascript not support typing/annotations
179
+ CONVERTER.TEST_EXCLUDE_NODES.extend(
180
+ [
181
+ ModuleImports.kind, # not use imports
182
+ ]
183
+ )
177
184
 
178
185
 
179
186
  # TODO: move to string_utils
@@ -213,8 +220,30 @@ def py_sequence_to_js_array(values: tuple[str, ...] | list[str]) -> str:
213
220
  return "[" + val_arr[1:-1] + "]"
214
221
 
215
222
 
216
- @CONVERTER(ModuleImports.kind)
217
- def pre_imports(_: ModuleImports) -> str:
223
+ @CONVERTER(ModuleTransformImports.kind)
224
+ def pre_transform_imports(node: ModuleTransformImports) -> str:
225
+ transforms, *_ = node.unpack_args()
226
+
227
+ if not transforms:
228
+ return ""
229
+
230
+ code_imports = []
231
+ for t in transforms:
232
+ if deps := t.collect_dependencies("js_pure"):
233
+ code_imports.append("\n".join(deps))
234
+ return "\n".join(code_imports)
235
+
236
+
237
+ @CONVERTER(ExprTransform.kind)
238
+ def pre_transform(node: ExprTransform) -> str:
239
+ # extend transform search provide py_bs4 module
240
+ prv, nxt = prev_next_var(node)
241
+ transform, *_ = node.unpack_args()
242
+ return "\n".join(f"{i};" for i in transform.emit("js_pure", prv, nxt))
243
+
244
+
245
+ @CONVERTER(ModuleUtilities.kind)
246
+ def pre_imports(_: ModuleUtilities) -> str:
218
247
  return HELPER_FUNCTIONS
219
248
 
220
249
 
@@ -28,6 +28,9 @@ from typing import Any, cast
28
28
 
29
29
  from ssc_codegen.ast_ import (
30
30
  Docstring,
31
+ ExprTransform,
32
+ ModuleTransformImports,
33
+ ModuleUtilities,
31
34
  StructParser,
32
35
  ExprReturn,
33
36
  ExprNoReturn,
@@ -187,6 +190,7 @@ CONVERTER.TEST_EXCLUDE_NODES.extend(
187
190
  FilterDocHasText.kind,
188
191
  FilterDocIsRegexText.kind,
189
192
  FilterDocIsRegexRaw.kind,
193
+ # NOT IMPLEMENTED
190
194
  ]
191
195
  )
192
196
 
@@ -291,7 +295,34 @@ def py_regex_to_lua_rex_pcre(
291
295
 
292
296
  @CONVERTER(ModuleImports.kind)
293
297
  def pre_imports(_: ModuleImports) -> str:
294
- return IMPORTS + "\n" + HELPER_FUNCTIONS
298
+ return IMPORTS
299
+
300
+
301
+ @CONVERTER(ModuleTransformImports.kind)
302
+ def pre_transform_imports(node: ModuleTransformImports) -> str:
303
+ transforms, *_ = node.unpack_args()
304
+
305
+ if not transforms:
306
+ return ""
307
+
308
+ code_imports = []
309
+ for t in transforms:
310
+ if deps := t.collect_dependencies("lua_htmlparser"):
311
+ code_imports.append("\n".join(deps))
312
+ return "\n".join(code_imports)
313
+
314
+
315
+ @CONVERTER(ModuleUtilities.kind)
316
+ def pre_utilities(_: ModuleUtilities) -> str:
317
+ return HELPER_FUNCTIONS
318
+
319
+
320
+ @CONVERTER(ExprTransform.kind)
321
+ def pre_transform(node: ExprTransform) -> str:
322
+ prv, nxt = prev_next_var(node)
323
+ transform, *_ = node.unpack_args()
324
+ parts = transform.emit("lua_htmlparser", prv, nxt)
325
+ return "\n" + "\n".join(parts)
295
326
 
296
327
 
297
328
  @CONVERTER(Docstring.kind)