@hexlabelposition/som 0.0.0-stage → 0.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vladyslav Kudriashov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,94 @@
1
- # Temporary Holding Version
1
+ # som
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **som (SVG Object Model)** is a zero-dependency, tree-shakeable ESM toolkit for working with SVG as plain objects in any JavaScript runtime.
4
+
5
+ > [!WARNING]
6
+ > **Status: pre-alpha.** som is in the design phase, and every API shown below is a draft that may change. See [BACKLOG.md](./BACKLOG.md) for what is planned and [ARCHITECTURE.md](./ARCHITECTURE.md) for how it is built.
7
+
8
+ ## Why
9
+
10
+ Working with SVG in JavaScript today usually means combining several packages: one to parse, one for paths, one for colors, one for bounds. Each has its own data format, its own types (or none), and often years without updates.
11
+
12
+ som aims to replace them with one coherent toolkit built around a single document model.
13
+
14
+ ## Principles
15
+
16
+ - **One library, one model.** Parse once, run any number of operations on the same tree, serialize once.
17
+ - **SVG as plain objects.** The tree is ordinary data with no DOM nodes or parent references: edit it with plain property access, store it as JSON or send it to a worker.
18
+ - **Lossless round trips.** Element order, text, comments, CDATA, processing instructions, the XML declaration, DOCTYPE, namespaces, attribute order, and unknown elements and attributes all survive `parse` → `stringify`.
19
+ - **Type-safe.** Strict public types, including element and attribute types generated from the SVG specifications.
20
+ - **Fast.** Single-pass parsing and minimal allocations, benchmarked against svgson and svg-parser. Published numbers come only from the benchmark suite.
21
+ - **Zero dependencies.** Pure JavaScript with no runtime dependencies and no DOM requirement.
22
+ - **ESM-only and tree-shakeable.** The API is made of independent functions without side effects, so a bundle contains only what you import: using `parse` does not pull in `stringify` or `colors`.
23
+
24
+ ## Guarantees
25
+
26
+ - **Strict parsing.** Only well-formed XML is accepted, and every error has a stable code and a source position.
27
+ - **Bounded parsing.** External entities are never loaded, and input size, nesting depth and entity expansion are limited.
28
+ - **No implicit interpretation.** Attribute values stay strings until a module explicitly parses them.
29
+ - **Tree-level round trips.** The tree is kept, not the exact source text: quote style, entity spelling and whitespace inside tags are normalized.
30
+
31
+ ## Planned features
32
+
33
+ | Area | What it covers | Planned for |
34
+ | -------------------------------------- | --------------------------------------------------------------------- | ----------- |
35
+ | **parse** | Parse SVG into an AST | v0.1 |
36
+ | **stringify** | Serialize an AST back to SVG | v0.1 |
37
+ | **ast** | `clone`, traversal, queries, type guards | v0.1 |
38
+ | **attributes** | Helpers for `style`, `class` and bulk attribute edits | v0.1 |
39
+ | **spec types** | Element and attribute types per SVG version, generated from the specs | v0.2 |
40
+ | **colors** | Extract, normalize and replace colors | v0.3 |
41
+ | **paths** | Parse, serialize and normalize path data (`d`) | v0.4 |
42
+ | **geometry, transforms, optimization** | Bounds, lengths, matrices, cleanup | later |
43
+
44
+ Versions show the intended order, not dates.
45
+
46
+ ## Usage (draft API)
47
+
48
+ ```ts
49
+ import { parse, stringify, getRoot } from "@hexlabelposition/som";
50
+
51
+ const doc = parse(
52
+ '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/></svg>',
53
+ );
54
+ const svg = getRoot(doc);
55
+
56
+ // The tree is plain data: edit it directly.
57
+ const circle = svg.children[0];
58
+ if (circle.type === "element") {
59
+ circle.attributes.fill = "currentColor";
60
+ }
61
+
62
+ stringify(doc);
63
+ // <svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="currentColor"/></svg>
64
+ ```
65
+
66
+ Operations mutate the document. When you need to keep the original, copy it explicitly:
67
+
68
+ ```ts
69
+ import { clone } from "@hexlabelposition/som";
70
+
71
+ const copy = clone(doc);
72
+ ```
73
+
74
+ Malformed input throws an `SvgParseError` with a stable `code` and the `line`, `column` and `offset` of the problem.
75
+
76
+ ## Runtimes
77
+
78
+ Node.js ≥ 22, Bun ≥ 1.2.23, Chromium, Firefox and WebKit, all tested in CI.
79
+
80
+ ## Non-goals
81
+
82
+ som is **not** a JSX parser, a renderer, a visual editor, or a sanitizer. Parsed documents keep scripts, event handlers and external references, so a document from an untrusted source must not be injected into a page as is. som works with SVG/XML markup, not JSX.
83
+
84
+ ## Name
85
+
86
+ **som** stands for **SVG Object Model**: SVG represented as a tree of plain objects. The project is called som; it is published on npm as `@hexlabelposition/som`, because the unscoped `som` name is taken.
87
+
88
+ ## Contributing
89
+
90
+ The project is not open for contributions yet. Development setup and conventions are described in [CONTRIBUTING.md](./CONTRIBUTING.md).
91
+
92
+ ## License
93
+
94
+ [MIT](./LICENSE)
@@ -0,0 +1 @@
1
+ export {}
package/dist/index.js ADDED
File without changes
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@hexlabelposition/som",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.0.0",
4
+ "description": "Zero-dependency, tree-shakeable ESM toolkit for working with SVG as plain objects",
5
+ "keywords": [
6
+ "svg",
7
+ "ast",
8
+ "parser",
9
+ "serializer",
10
+ "xml"
11
+ ],
12
+ "homepage": "https://github.com/hexlabelposition/som#readme",
13
+ "bugs": "https://github.com/hexlabelposition/som/issues",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/hexlabelposition/som.git"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Vladyslav Kudriashov",
20
+ "type": "module",
21
+ "sideEffects": false,
22
+ "exports": {
23
+ ".": "./dist/index.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "engines": {
30
+ "node": ">=22"
31
+ },
32
+ "packageManager": "bun@1.4.0",
33
+ "scripts": {
34
+ "build": "tsdown",
35
+ "prepack": "bun run build",
36
+ "typecheck": "tsc -p tsconfig.lib.json && tsc -p tsconfig.test.json && tsc -p tsconfig.scripts.json",
37
+ "test": "vitest run",
38
+ "test:node": "vitest run --project node",
39
+ "test:browser": "vitest run --project browser",
40
+ "lint": "eslint .",
41
+ "format": "prettier --write .",
42
+ "format:check": "prettier --check . '!**/*.md'",
43
+ "docs:check": "prettier --check '**/*.md'"
44
+ },
45
+ "devDependencies": {
46
+ "@arethetypeswrong/core": "^0.18.5",
47
+ "@eslint/js": "^10.0.1",
48
+ "@types/node": "^22.20.5",
49
+ "@vitest/browser-playwright": "^5.0.5",
50
+ "eslint": "^10.13.0",
51
+ "eslint-config-prettier": "^10.1.8",
52
+ "eslint-plugin-boundaries": "^7.3.0",
53
+ "fast-check": "^4.10.2",
54
+ "jiti": "^2.7.0",
55
+ "playwright": "1.64.1",
56
+ "prettier": "^3.9.10",
57
+ "publint": "^0.3.25",
58
+ "tsdown": "^0.23.2",
59
+ "typescript": "~6.0.3",
60
+ "typescript-eslint": "^8.72.0",
61
+ "vitest": "^5.0.5"
62
+ }
63
+ }