st-creator 0.2.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.
- st_creator-0.2.0/PKG-INFO +180 -0
- st_creator-0.2.0/README.md +170 -0
- st_creator-0.2.0/pyproject.toml +27 -0
- st_creator-0.2.0/src/st_creator/__init__.py +16 -0
- st_creator-0.2.0/src/st_creator/commands/__init__.py +0 -0
- st_creator-0.2.0/src/st_creator/commands/theme.py +137 -0
- st_creator-0.2.0/src/st_creator/commands/version.py +9 -0
- st_creator-0.2.0/src/st_creator/core/__init__.py +0 -0
- st_creator-0.2.0/src/st_creator/core/model.py +355 -0
- st_creator-0.2.0/src/st_creator/core/rule_parser.py +649 -0
- st_creator-0.2.0/src/st_creator/core/theme_attributes.py +34 -0
- st_creator-0.2.0/src/st_creator/utils/__init__.py +0 -0
- st_creator-0.2.0/src/st_creator/utils/colors.py +40 -0
- st_creator-0.2.0/src/st_creator/utils/config.py +45 -0
- st_creator-0.2.0/src/st_creator/utils/pretty_print.py +87 -0
- st_creator-0.2.0/src/st_creator/utils/str_utils.py +156 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: st-creator
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A stupid CLI to easily create themes for Structurizr.
|
|
5
|
+
Author: Federico Cantarelli
|
|
6
|
+
Author-email: Federico Cantarelli <fede.cantarelli98@gmail.com>
|
|
7
|
+
Requires-Dist: click>=8.4.2,<9.0.0
|
|
8
|
+
Requires-Python: >=3.13
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# Structurizr Theme Creator
|
|
12
|
+
|
|
13
|
+
A very stupid CLI to create Structurizr themes starting from icons.
|
|
14
|
+
|
|
15
|
+
<b>:warning: This is super work in progress. Will be completed soon.</b>
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
`st` is not published to PyPI yet, so you can install it directly from the repository using [`uv`](https://docs.astral.sh/uv/).
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Clone the repository
|
|
23
|
+
git clone https://github.com/FedericoCantarelli/st.git
|
|
24
|
+
cd st
|
|
25
|
+
|
|
26
|
+
# Install dependencies and create the virtual environment
|
|
27
|
+
uv sync
|
|
28
|
+
|
|
29
|
+
# Run the CLI using uv
|
|
30
|
+
uv run st --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If you want to have `st` command available directly from CLI, you can install the tool running the following command from the root of the repository:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv tool install .
|
|
37
|
+
st --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
The CLI is enterile based on `click` module. To get CLI help you can run the following command:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
st --help
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Version
|
|
48
|
+
Print the CLI version
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
st version
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Clean
|
|
55
|
+
Normalizes a raw icon export (e.g. downloaded from an icon library) into a directory of `cleaned_string`-named files and directories, ready to be fed into `st theme create`. See [Naming Convention](#naming-convention-of-exported-icons) for how output names are derived. Hidden files and directories (starting with `.`) are <u>skipped</u>.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
st theme clean <path> [--output <dir>] [--rules <rules.st>]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Argument / Option | Required | Description |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `path` | Yes | Path to the input directory containing the raw icon export. Must exist. |
|
|
64
|
+
| `--output` | No | Name of the output directory, created as a sibling of `path`. Defaults to `cleaned`. |
|
|
65
|
+
| `--rules` | No | Path to a [rules file](#rules-dsl) used to filter which icons are processed. |
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
st theme clean ./raw-icons --output cleaned --rules ./rules.st
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Create
|
|
74
|
+
|
|
75
|
+
Create a theme from a cleaned icon directory, builds one theme element per `.svg` file found, and exports a `theme.json` compatible with Structurizr's [custom theme](https://docs.structurizr.com/dsl/themes) format. The output is written to a new directory named after `--name` (lowercased, spaces replaced with `-`), placed as a sibling of `path`.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
st theme create <path> --name "My Theme" [--description <text>] [--rules <rules.st>]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
| Argument / Option | Required | Description |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| `path` | Yes | Path to the input directory containing the icons to include in the theme. Must exist. |
|
|
84
|
+
| `--name` | Yes | Name of the theme. Also used to derive the file prefix and tag prefix (see [Naming Convention](#naming-convention-of-exported-icons)). |
|
|
85
|
+
| `--description` | No | Description of the theme, written into `theme.json`. |
|
|
86
|
+
| `--rules` | No | Path to a [rules file](#rules-dsl) used to filter which icons are processed. |
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
st theme create ./cleaned --name "GCP Icons" --description "Google Cloud Platform icon theme" --rules ./rules.st
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
On first run, `st theme create` creates a default configuration file at `~/.st/config.ini` if one does not already exist. For the moment this file is unusued. TODO: implement default configuration options in this file.
|
|
95
|
+
|
|
96
|
+
## Naming Convention of Exported Icons
|
|
97
|
+
|
|
98
|
+
The naming convention of exported icons depends on the directory structure of the icons: exported icon names depend on the first-level nested directories inside the input directory.
|
|
99
|
+
|
|
100
|
+
Given the following project structure:
|
|
101
|
+
```text
|
|
102
|
+
# First level nested directories are `Category Icons` and `Unique Icons`
|
|
103
|
+
.
|
|
104
|
+
├── Category Icons
|
|
105
|
+
│ └── Agents
|
|
106
|
+
│ ├── PNG
|
|
107
|
+
│ │ └── Agents-512-color.png
|
|
108
|
+
│ └── SVG
|
|
109
|
+
│ └── Agents-512-color.svg
|
|
110
|
+
└── Unique Icons
|
|
111
|
+
└── AlloyDB
|
|
112
|
+
├── PNG
|
|
113
|
+
│ └── AlloyDB-512-color.png
|
|
114
|
+
└── SVG
|
|
115
|
+
└── AlloyDB-512-color.svg
|
|
116
|
+
```
|
|
117
|
+
The naming convention for the exported icons is the following:
|
|
118
|
+
```
|
|
119
|
+
<prefix>_<first_level_dir>_<snake_case_filename>
|
|
120
|
+
```
|
|
121
|
+
where `<prefix>` is computed from theme name, `<first_level_dir>` is the name of the first-level nested directory in snake case, and `<snake_case_filename>` is the filename converted to snake case, removing everything else that is not a character (number or non-alphanumeric characters).
|
|
122
|
+
|
|
123
|
+
For example the file `AlloyDB-512-color.png` will be exported as `gcp_unique_icons_alloydb_color.png` if the theme name is `Google Cloud Platform`.
|
|
124
|
+
|
|
125
|
+
Only the top-level directory (one level inside the `--path` folder) is used for the naming convention.
|
|
126
|
+
|
|
127
|
+
For `st theme create`, the `--name` you pass also drives two additional prefixes:
|
|
128
|
+
- **Tag prefix**: used to prefix the Structurizr element tag (e.g. `GCP - Category - Agents`). If the theme name has more than two "eligible" words (longer than 2 characters), the prefix is the initials of those words; otherwise it's the whole name in snake case.
|
|
129
|
+
- **File prefix**: same derivation logic, used to prefix the icon file name and the theme's output directory.
|
|
130
|
+
|
|
131
|
+
## Rules DSL
|
|
132
|
+
Both `st theme clean` and `st theme create` accept an optional `--rules <path>` argument pointing to a rules file (conventionally named `rules.st`). Rules let you filter which icons get processed without having to restructure your input directory. TODO: eventually this can become a `.txt` for the mental health of everybody.
|
|
133
|
+
|
|
134
|
+
A rules file is a sequence of `INCLUDE(<expr>)` / `EXCLUDE(<expr>)` statements, one or more per file. `<expr>` is a boolean expression built from `AND`, `OR`, `NOT`, parentheses, and two kinds of leaf predicates:
|
|
135
|
+
|
|
136
|
+
- `ATTRIBUTE=value` — glob-matches `value` against an icon attribute. Supports `*` (any sequence of characters, including none), `?` (any single character), and `[...]` / `[!...]` character classes (with `-` for ranges, e.g. `[a-z]`).
|
|
137
|
+
- `CONTAIN(ATTRIBUTE, "substring")` — true if the attribute's value contains `substring` as a literal substring.
|
|
138
|
+
|
|
139
|
+
`ATTRIBUTE` is one of:
|
|
140
|
+
|
|
141
|
+
| Attribute | Description |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `NAME` | The icon's file name without its extension. |
|
|
144
|
+
| `EXTENSION` | The icon's file extension, including the leading dot (e.g. `.svg`). |
|
|
145
|
+
| `PATH` | The icon's full path, as a POSIX-style string. |
|
|
146
|
+
|
|
147
|
+
Matching is **case-sensitive**. Values are written either as bare words or quoted strings (`'...'` or `"..."`); quoting is required for values containing spaces or reserved characters. This set of attributes is meant to be extensible and will be expanded (hopefully) in future versions of the CLI to allow more specific rules.
|
|
148
|
+
|
|
149
|
+
### Decision rule
|
|
150
|
+
|
|
151
|
+
An icon is dropped if it matches any `EXCLUDE` expression, unless it also matches an `INCLUDE` expression. Thus `INCLUDE` always overrides `EXCLUDE` on conflict. Default is keep: if an icon matches neither an `INCLUDE` nor an `EXCLUDE` expression is kept.
|
|
152
|
+
|
|
153
|
+
If a rules file has `INCLUDE` statements but **no** `EXCLUDE` statements, `INCLUDE` acts as a standalone whitelist: only icons matching at least one `INCLUDE` expression are kept
|
|
154
|
+
- 'INCLUDE' acts as a filter in
|
|
155
|
+
- 'EXCLUDE' acts as a filter out
|
|
156
|
+
Thus 'EXCLUDE(NOT NAME="file_name.svg") will include the file_name.svg and exclude all the others.
|
|
157
|
+
|
|
158
|
+
I'm not sure if this is the best approach, but i wrote it like this.
|
|
159
|
+
|
|
160
|
+
### Examples
|
|
161
|
+
|
|
162
|
+
Keep only `.svg` files, and drop anything under a directory called `Unique Icons`, unless its file name starts with `Alloy`:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
INCLUDE(NAME="Alloy*" AND EXTENSION=".svg")
|
|
166
|
+
EXCLUDE(CONTAIN(PATH, "Unique Icons"))
|
|
167
|
+
EXCLUDE(NOT EXTENSION=".svg")
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Whitelist a single file, dropping everything else:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
INCLUDE(NAME="filename")
|
|
174
|
+
EXCLUDE(NAME="*")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Exclude every file whose name contains 'deprecated'
|
|
178
|
+
```
|
|
179
|
+
EXCLUDE(CONTAIN(NAME, "deprecated"))
|
|
180
|
+
```
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Structurizr Theme Creator
|
|
2
|
+
|
|
3
|
+
A very stupid CLI to create Structurizr themes starting from icons.
|
|
4
|
+
|
|
5
|
+
<b>:warning: This is super work in progress. Will be completed soon.</b>
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
`st` is not published to PyPI yet, so you can install it directly from the repository using [`uv`](https://docs.astral.sh/uv/).
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Clone the repository
|
|
13
|
+
git clone https://github.com/FedericoCantarelli/st.git
|
|
14
|
+
cd st
|
|
15
|
+
|
|
16
|
+
# Install dependencies and create the virtual environment
|
|
17
|
+
uv sync
|
|
18
|
+
|
|
19
|
+
# Run the CLI using uv
|
|
20
|
+
uv run st --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If you want to have `st` command available directly from CLI, you can install the tool running the following command from the root of the repository:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install .
|
|
27
|
+
st --help
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
The CLI is enterile based on `click` module. To get CLI help you can run the following command:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
st --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Version
|
|
38
|
+
Print the CLI version
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
st version
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Clean
|
|
45
|
+
Normalizes a raw icon export (e.g. downloaded from an icon library) into a directory of `cleaned_string`-named files and directories, ready to be fed into `st theme create`. See [Naming Convention](#naming-convention-of-exported-icons) for how output names are derived. Hidden files and directories (starting with `.`) are <u>skipped</u>.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
st theme clean <path> [--output <dir>] [--rules <rules.st>]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Argument / Option | Required | Description |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `path` | Yes | Path to the input directory containing the raw icon export. Must exist. |
|
|
54
|
+
| `--output` | No | Name of the output directory, created as a sibling of `path`. Defaults to `cleaned`. |
|
|
55
|
+
| `--rules` | No | Path to a [rules file](#rules-dsl) used to filter which icons are processed. |
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
st theme clean ./raw-icons --output cleaned --rules ./rules.st
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Create
|
|
64
|
+
|
|
65
|
+
Create a theme from a cleaned icon directory, builds one theme element per `.svg` file found, and exports a `theme.json` compatible with Structurizr's [custom theme](https://docs.structurizr.com/dsl/themes) format. The output is written to a new directory named after `--name` (lowercased, spaces replaced with `-`), placed as a sibling of `path`.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
st theme create <path> --name "My Theme" [--description <text>] [--rules <rules.st>]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Argument / Option | Required | Description |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `path` | Yes | Path to the input directory containing the icons to include in the theme. Must exist. |
|
|
74
|
+
| `--name` | Yes | Name of the theme. Also used to derive the file prefix and tag prefix (see [Naming Convention](#naming-convention-of-exported-icons)). |
|
|
75
|
+
| `--description` | No | Description of the theme, written into `theme.json`. |
|
|
76
|
+
| `--rules` | No | Path to a [rules file](#rules-dsl) used to filter which icons are processed. |
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
st theme create ./cleaned --name "GCP Icons" --description "Google Cloud Platform icon theme" --rules ./rules.st
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
On first run, `st theme create` creates a default configuration file at `~/.st/config.ini` if one does not already exist. For the moment this file is unusued. TODO: implement default configuration options in this file.
|
|
85
|
+
|
|
86
|
+
## Naming Convention of Exported Icons
|
|
87
|
+
|
|
88
|
+
The naming convention of exported icons depends on the directory structure of the icons: exported icon names depend on the first-level nested directories inside the input directory.
|
|
89
|
+
|
|
90
|
+
Given the following project structure:
|
|
91
|
+
```text
|
|
92
|
+
# First level nested directories are `Category Icons` and `Unique Icons`
|
|
93
|
+
.
|
|
94
|
+
├── Category Icons
|
|
95
|
+
│ └── Agents
|
|
96
|
+
│ ├── PNG
|
|
97
|
+
│ │ └── Agents-512-color.png
|
|
98
|
+
│ └── SVG
|
|
99
|
+
│ └── Agents-512-color.svg
|
|
100
|
+
└── Unique Icons
|
|
101
|
+
└── AlloyDB
|
|
102
|
+
├── PNG
|
|
103
|
+
│ └── AlloyDB-512-color.png
|
|
104
|
+
└── SVG
|
|
105
|
+
└── AlloyDB-512-color.svg
|
|
106
|
+
```
|
|
107
|
+
The naming convention for the exported icons is the following:
|
|
108
|
+
```
|
|
109
|
+
<prefix>_<first_level_dir>_<snake_case_filename>
|
|
110
|
+
```
|
|
111
|
+
where `<prefix>` is computed from theme name, `<first_level_dir>` is the name of the first-level nested directory in snake case, and `<snake_case_filename>` is the filename converted to snake case, removing everything else that is not a character (number or non-alphanumeric characters).
|
|
112
|
+
|
|
113
|
+
For example the file `AlloyDB-512-color.png` will be exported as `gcp_unique_icons_alloydb_color.png` if the theme name is `Google Cloud Platform`.
|
|
114
|
+
|
|
115
|
+
Only the top-level directory (one level inside the `--path` folder) is used for the naming convention.
|
|
116
|
+
|
|
117
|
+
For `st theme create`, the `--name` you pass also drives two additional prefixes:
|
|
118
|
+
- **Tag prefix**: used to prefix the Structurizr element tag (e.g. `GCP - Category - Agents`). If the theme name has more than two "eligible" words (longer than 2 characters), the prefix is the initials of those words; otherwise it's the whole name in snake case.
|
|
119
|
+
- **File prefix**: same derivation logic, used to prefix the icon file name and the theme's output directory.
|
|
120
|
+
|
|
121
|
+
## Rules DSL
|
|
122
|
+
Both `st theme clean` and `st theme create` accept an optional `--rules <path>` argument pointing to a rules file (conventionally named `rules.st`). Rules let you filter which icons get processed without having to restructure your input directory. TODO: eventually this can become a `.txt` for the mental health of everybody.
|
|
123
|
+
|
|
124
|
+
A rules file is a sequence of `INCLUDE(<expr>)` / `EXCLUDE(<expr>)` statements, one or more per file. `<expr>` is a boolean expression built from `AND`, `OR`, `NOT`, parentheses, and two kinds of leaf predicates:
|
|
125
|
+
|
|
126
|
+
- `ATTRIBUTE=value` — glob-matches `value` against an icon attribute. Supports `*` (any sequence of characters, including none), `?` (any single character), and `[...]` / `[!...]` character classes (with `-` for ranges, e.g. `[a-z]`).
|
|
127
|
+
- `CONTAIN(ATTRIBUTE, "substring")` — true if the attribute's value contains `substring` as a literal substring.
|
|
128
|
+
|
|
129
|
+
`ATTRIBUTE` is one of:
|
|
130
|
+
|
|
131
|
+
| Attribute | Description |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| `NAME` | The icon's file name without its extension. |
|
|
134
|
+
| `EXTENSION` | The icon's file extension, including the leading dot (e.g. `.svg`). |
|
|
135
|
+
| `PATH` | The icon's full path, as a POSIX-style string. |
|
|
136
|
+
|
|
137
|
+
Matching is **case-sensitive**. Values are written either as bare words or quoted strings (`'...'` or `"..."`); quoting is required for values containing spaces or reserved characters. This set of attributes is meant to be extensible and will be expanded (hopefully) in future versions of the CLI to allow more specific rules.
|
|
138
|
+
|
|
139
|
+
### Decision rule
|
|
140
|
+
|
|
141
|
+
An icon is dropped if it matches any `EXCLUDE` expression, unless it also matches an `INCLUDE` expression. Thus `INCLUDE` always overrides `EXCLUDE` on conflict. Default is keep: if an icon matches neither an `INCLUDE` nor an `EXCLUDE` expression is kept.
|
|
142
|
+
|
|
143
|
+
If a rules file has `INCLUDE` statements but **no** `EXCLUDE` statements, `INCLUDE` acts as a standalone whitelist: only icons matching at least one `INCLUDE` expression are kept
|
|
144
|
+
- 'INCLUDE' acts as a filter in
|
|
145
|
+
- 'EXCLUDE' acts as a filter out
|
|
146
|
+
Thus 'EXCLUDE(NOT NAME="file_name.svg") will include the file_name.svg and exclude all the others.
|
|
147
|
+
|
|
148
|
+
I'm not sure if this is the best approach, but i wrote it like this.
|
|
149
|
+
|
|
150
|
+
### Examples
|
|
151
|
+
|
|
152
|
+
Keep only `.svg` files, and drop anything under a directory called `Unique Icons`, unless its file name starts with `Alloy`:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
INCLUDE(NAME="Alloy*" AND EXTENSION=".svg")
|
|
156
|
+
EXCLUDE(CONTAIN(PATH, "Unique Icons"))
|
|
157
|
+
EXCLUDE(NOT EXTENSION=".svg")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Whitelist a single file, dropping everything else:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
INCLUDE(NAME="filename")
|
|
164
|
+
EXCLUDE(NAME="*")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Exclude every file whose name contains 'deprecated'
|
|
168
|
+
```
|
|
169
|
+
EXCLUDE(CONTAIN(NAME, "deprecated"))
|
|
170
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "st-creator"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "A stupid CLI to easily create themes for Structurizr."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Federico Cantarelli", email = "fede.cantarelli98@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.13"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"click>=8.4.2,<9.0.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
st = "st_creator:main"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["uv_build>=0.11.28,<0.12.0"]
|
|
19
|
+
build-backend = "uv_build"
|
|
20
|
+
|
|
21
|
+
[tool.commitizen]
|
|
22
|
+
name = "cz_conventional_commits"
|
|
23
|
+
tag_format = "$version"
|
|
24
|
+
version_scheme = "semver2"
|
|
25
|
+
version_provider = "uv"
|
|
26
|
+
update_changelog_on_bump = true
|
|
27
|
+
major_version_zero = true
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from st.commands.theme import theme
|
|
4
|
+
from st.commands.version import version
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.group()
|
|
8
|
+
def main():
|
|
9
|
+
"""ST: A command line tool for creating Structurizr themes easily."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
main.add_command(version)
|
|
13
|
+
main.add_command(theme)
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from st.core.model import Theme
|
|
7
|
+
from st.core.model import ThemeElement
|
|
8
|
+
from st.core.model import go_through_fs_tree
|
|
9
|
+
from st.core.rule_parser import RuleSet
|
|
10
|
+
from st.core.rule_parser import filter_elements
|
|
11
|
+
from st.utils.config import CONFIG_FILE
|
|
12
|
+
from st.utils.config import init_config
|
|
13
|
+
from st.utils.config import load_config
|
|
14
|
+
from st.utils.pretty_print import print_done
|
|
15
|
+
from st.utils.pretty_print import print_verbose
|
|
16
|
+
from st.utils.pretty_print import print_warning
|
|
17
|
+
from st.utils.str_utils import to_clean_string
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@click.group()
|
|
21
|
+
def theme():
|
|
22
|
+
"""Create a DSL theme."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@theme.command()
|
|
26
|
+
@click.argument("path", type=click.Path(exists=True))
|
|
27
|
+
@click.option("--output", type=click.Path(), required=False, default=None)
|
|
28
|
+
@click.option(
|
|
29
|
+
"--rules",
|
|
30
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
31
|
+
required=False,
|
|
32
|
+
default=None,
|
|
33
|
+
help="Path to a rules file (e.g. rules.st) filtering which icons to process.",
|
|
34
|
+
)
|
|
35
|
+
def clean(path, output, rules):
|
|
36
|
+
"""Prepare a directory of icons for theme creation."""
|
|
37
|
+
full_path = pathlib.Path(path)
|
|
38
|
+
output_path = full_path.parent / (output if output else "cleaned")
|
|
39
|
+
if not output_path.exists():
|
|
40
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
first_level = [item for item in os.listdir(full_path) if not item.startswith(".")]
|
|
42
|
+
first_level_dict = {item: to_clean_string(item) for item in first_level}
|
|
43
|
+
for item in first_level_dict.values():
|
|
44
|
+
if item.startswith("."):
|
|
45
|
+
print_verbose(f"Skipping hidden directory: {item}")
|
|
46
|
+
else:
|
|
47
|
+
if item is not None:
|
|
48
|
+
os.makedirs(os.path.join(output_path, item), exist_ok=True)
|
|
49
|
+
elements = go_through_fs_tree(
|
|
50
|
+
full_path=full_path, include_top_parent_directory=False
|
|
51
|
+
)
|
|
52
|
+
if rules is not None:
|
|
53
|
+
elements = filter_elements(elements, RuleSet.from_file(pathlib.Path(rules)))
|
|
54
|
+
for element in elements:
|
|
55
|
+
element.copy(
|
|
56
|
+
output_path=output_path
|
|
57
|
+
/ element.top_parent_directory
|
|
58
|
+
/ element.cleaned_file_name
|
|
59
|
+
if element.top_parent_directory
|
|
60
|
+
else output_path / element.cleaned_file_name
|
|
61
|
+
)
|
|
62
|
+
print_done("Cleaning done!")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@theme.command()
|
|
66
|
+
@click.argument("path", type=click.Path(exists=True))
|
|
67
|
+
@click.option("--name", type=str, required=True)
|
|
68
|
+
@click.option("--description", type=str, required=False, default=None)
|
|
69
|
+
@click.option(
|
|
70
|
+
"--rules",
|
|
71
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
72
|
+
required=False,
|
|
73
|
+
default=None,
|
|
74
|
+
help="Path to a rules file (e.g. rules.st) filtering which icons to process.",
|
|
75
|
+
)
|
|
76
|
+
def create(path, name: str, description: str | None, rules: str) -> None:
|
|
77
|
+
if not CONFIG_FILE.exists():
|
|
78
|
+
print_warning("Configuration file not found. Creating one with default values.")
|
|
79
|
+
init_config(config_path=CONFIG_FILE)
|
|
80
|
+
config = load_config(config_path=CONFIG_FILE)
|
|
81
|
+
full_path = pathlib.Path(path).resolve()
|
|
82
|
+
output_path = full_path.parent / "-".join(name.lower().split(" "))
|
|
83
|
+
|
|
84
|
+
name = name.replace("'", "").replace('"', "")
|
|
85
|
+
description = (
|
|
86
|
+
description.replace("'", "").replace('"', "")
|
|
87
|
+
if description is not None
|
|
88
|
+
else None
|
|
89
|
+
)
|
|
90
|
+
os.makedirs(os.path.join(output_path), exist_ok=True)
|
|
91
|
+
theme = Theme(
|
|
92
|
+
name="Name here" if name is None else name,
|
|
93
|
+
description="Description here" if description is None else description,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
elements = go_through_fs_tree(
|
|
97
|
+
full_path=full_path,
|
|
98
|
+
include_top_parent_directory=False,
|
|
99
|
+
)
|
|
100
|
+
if rules is not None:
|
|
101
|
+
elements = filter_elements(elements, RuleSet.from_file(pathlib.Path(rules)))
|
|
102
|
+
|
|
103
|
+
for element in elements:
|
|
104
|
+
element.copy(
|
|
105
|
+
output_path=output_path / (theme.file_prefix + "_" + element.theme_name),
|
|
106
|
+
)
|
|
107
|
+
element.load_properties_from_json()
|
|
108
|
+
|
|
109
|
+
theme_element = ThemeElement(
|
|
110
|
+
tag=element.get_theme_tag(prefix=theme.tag_prefix),
|
|
111
|
+
# stroke=color
|
|
112
|
+
# if color is not None
|
|
113
|
+
# else config["defaults.theme"]["stroke"],
|
|
114
|
+
# color=color if color is not None else config["defaults.theme"]["color"],
|
|
115
|
+
stroke="#232f3d",
|
|
116
|
+
color="#232f3d",
|
|
117
|
+
icon=theme.file_prefix + "_" + element.theme_name,
|
|
118
|
+
)
|
|
119
|
+
theme.add_element(theme_element)
|
|
120
|
+
|
|
121
|
+
theme.export(pathlib.Path(output_path) / "theme.json")
|
|
122
|
+
|
|
123
|
+
print_done("Theme created!")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# TODO: keep this for future releases maybe >^.^<
|
|
127
|
+
# @click.command()
|
|
128
|
+
# @click.option("--output", type=click.Path(), required=True)
|
|
129
|
+
# def scrape(output) -> None:
|
|
130
|
+
# print(f"Scraping icons from {TECH_ICON_URL}\n")
|
|
131
|
+
# time.sleep(1)
|
|
132
|
+
# if download_blob_image(
|
|
133
|
+
# base_url=TECH_ICON_URL, output_dir=pathlib.Path(output).resolve()
|
|
134
|
+
# ):
|
|
135
|
+
# print_done("\nAll images downloaded successfully!")
|
|
136
|
+
# else:
|
|
137
|
+
# print_warning("\nDownload failed")
|
|
File without changes
|