schematic-symbols 0.0.7 → 0.0.9

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.
Files changed (42) hide show
  1. package/dist/index.cjs +1697 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +79 -0
  4. package/package.json +9 -2
  5. package/symbols/diode_horz.ts +18 -0
  6. package/symbols/diode_vert.ts +4 -0
  7. package/symbols/index.ts +4 -0
  8. package/.github/CODEOWNERS +0 -1
  9. package/.github/workflows/bun-formatcheck.yml +0 -26
  10. package/.github/workflows/bun-pver-release.yml +0 -27
  11. package/.github/workflows/bun-typecheck.yml +0 -26
  12. package/.github/workflows/formatbot.yml +0 -49
  13. package/assets/symbols-svg-json/boxresistor.json +0 -90
  14. package/assets/symbols-svg-json/capacitor.json +0 -76
  15. package/assets/symbols-svg-json/capacitor_polarized.json +0 -83
  16. package/assets/symbols-svg-json/diode.json +0 -91
  17. package/assets/symbols-svg-json/diode_bipolar_zener.json +0 -166
  18. package/assets/symbols-svg-json/diode_schottky.json +0 -76
  19. package/assets/symbols-svg-json/diode_zener.json +0 -31
  20. package/assets/symbols-svg-json/fuse.json +0 -84
  21. package/assets/symbols-svg-json/led.json +0 -205
  22. package/assets/symbols-svg-json/mosfet_depletion_normally_on.json +0 -267
  23. package/assets/symbols-svg-json/potentiometer.json +0 -137
  24. package/assets/symbols-svg-json/potentiometer2.json +0 -160
  25. package/assets/symbols-svg-json/testshape.json +0 -35
  26. package/assets/symbols-svg-json/varistor.json +0 -129
  27. package/assets/symbols.svg +0 -965
  28. package/biome.json +0 -44
  29. package/bun.lockb +0 -0
  30. package/dev-server.ts +0 -22
  31. package/scripts/build.ts +0 -18
  32. package/scripts/convertToObjectWithOrderedPositionIds.ts +0 -52
  33. package/scripts/generate-symbols-from-asset-svgs.ts +0 -146
  34. package/scripts/lib/applyGroupTransformsToChildren.ts +0 -119
  35. package/scripts/lib/findInnerText.ts +0 -11
  36. package/scripts/lib/generate-web-page.ts +0 -60
  37. package/scripts/lib/getTsFileContentForSvgGroup.ts +0 -33
  38. package/scripts/lib/serializeSvgPathCommands.ts +0 -48
  39. package/tests/assets/boxresistor-untransformed.json +0 -187
  40. package/tests/assets/testshape-untransformed.json +0 -25
  41. package/tests/normalize-svg.test.ts +0 -29
  42. package/tsconfig.json +0 -28
package/biome.json DELETED
@@ -1,44 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
3
- "organizeImports": {
4
- "enabled": true
5
- },
6
- "formatter": {
7
- "enabled": true,
8
- "indentStyle": "space"
9
- },
10
- "files": {
11
- "ignore": ["cosmos-export", "dist", "package.json"]
12
- },
13
- "javascript": {
14
- "formatter": {
15
- "jsxQuoteStyle": "double",
16
- "quoteProperties": "asNeeded",
17
- "trailingCommas": "all",
18
- "semicolons": "asNeeded",
19
- "arrowParentheses": "always",
20
- "bracketSpacing": true,
21
- "bracketSameLine": false
22
- }
23
- },
24
- "linter": {
25
- "enabled": false,
26
- "rules": {
27
- "recommended": true,
28
- "suspicious": {
29
- "noExplicitAny": "off"
30
- },
31
- "style": {
32
- "noNonNullAssertion": "off",
33
- "useFilenamingConvention": {
34
- "level": "error",
35
- "options": {
36
- "strictCase": true,
37
- "requireAscii": true,
38
- "filenameCases": ["kebab-case", "export"]
39
- }
40
- }
41
- }
42
- }
43
- }
44
- }
package/bun.lockb DELETED
Binary file
package/dev-server.ts DELETED
@@ -1,22 +0,0 @@
1
- import { generateWebPage } from "./scripts/lib/generate-web-page"
2
-
3
- console.log(`Serving on http://localhost:3077`)
4
- Bun.serve({
5
- port: 3077,
6
- async fetch(req) {
7
- const url = new URL(req.url)
8
-
9
- if (url.pathname === "/") {
10
- const html = generateWebPage()
11
- return new Response(html, {
12
- headers: { "Content-Type": "text/html" },
13
- })
14
- }
15
-
16
- // Serve static files
17
- return new Response("", {
18
- status: 404,
19
- })
20
- // return new Response(await Bun.file(url.pathname))
21
- },
22
- })
package/scripts/build.ts DELETED
@@ -1,18 +0,0 @@
1
- import { generateWebPage } from "./lib/generate-web-page"
2
- import fs from "fs"
3
- import path from "path"
4
-
5
- const distDir = path.join(process.cwd(), "public")
6
-
7
- // Ensure the dist directory exists
8
- if (!fs.existsSync(distDir)) {
9
- fs.mkdirSync(distDir, { recursive: true })
10
- }
11
-
12
- // Generate the HTML content
13
- const htmlContent = generateWebPage()
14
-
15
- // Write the HTML content to dist/index.html
16
- fs.writeFileSync(path.join(distDir, "index.html"), htmlContent)
17
-
18
- console.log("Static HTML file generated at public/index.html")
@@ -1,52 +0,0 @@
1
- export const convertToObjectWithOrderedPositionIds = <
2
- T extends { x: number; y: number },
3
- >(
4
- points: T[],
5
- ): Record<string, T> => {
6
- const result: Record<string, T> = {}
7
-
8
- const sides = {
9
- top: [] as T[],
10
- bottom: [] as T[],
11
- left: [] as T[],
12
- right: [] as T[],
13
- unknown: [] as T[],
14
- }
15
-
16
- for (const point of points) {
17
- const dx = point.x
18
- const dy = point.y
19
-
20
- const dominantSide = Math.abs(dx) > Math.abs(dy) ? "x" : "y"
21
-
22
- let side: "top" | "bottom" | "left" | "right" | "unknown"
23
- if (dominantSide === "x" && dx > 0) {
24
- side = "right"
25
- } else if (dominantSide === "x" && dx < 0) {
26
- side = "left"
27
- } else if (dominantSide === "y" && dy > 0) {
28
- side = "bottom"
29
- } else if (dominantSide === "y" && dy < 0) {
30
- side = "top"
31
- } else {
32
- side = "unknown"
33
- }
34
-
35
- sides[side].push(point)
36
- }
37
-
38
- // Sort each side according to x or y
39
- sides.top.sort((a, b) => a.x - b.x)
40
- sides.bottom.sort((a, b) => a.x - b.x)
41
- sides.left.sort((a, b) => a.y - b.y)
42
- sides.right.sort((a, b) => a.y - b.y)
43
-
44
- // Assign position ids to each point
45
- for (const side of Object.keys(sides)) {
46
- for (let i = 0; i < sides[side as keyof typeof sides].length; i++) {
47
- result[`${side}${i + 1}`] = sides[side as keyof typeof sides][i]
48
- }
49
- }
50
-
51
- return result
52
- }
@@ -1,146 +0,0 @@
1
- // @ts-ignore
2
- import symbolsSvg from "../assets/symbols.svg" with { type: "text" }
3
- import { parse, type INode } from "svgson"
4
- import fs from "node:fs"
5
- import { applyGroupTransformsToChildren } from "./lib/applyGroupTransformsToChildren"
6
- import { getBoundsOfSvgJson } from "drawing/getBoundsOfSvgJson"
7
- import { compose, translate, toSVG, scale } from "transformation-matrix"
8
- import { convertToObjectWithOrderedPositionIds } from "./convertToObjectWithOrderedPositionIds"
9
- import { findInnerText } from "./lib/findInnerText"
10
- import { svgPathToPoints, type SvgData } from "drawing"
11
- import { getTsFileContentForSvgGroup } from "./lib/getTsFileContentForSvgGroup"
12
-
13
- const SOURCE_IGNORE_LIST = ["testshape"]
14
-
15
- async function processSvg() {
16
- try {
17
- // Parse the entire SVG file once
18
- const parsedSvg = await parse(symbolsSvg)
19
-
20
- // Find the root group
21
- const rootGroup = parsedSvg.children.find(
22
- (child) => child.name === "g" && child.attributes.id === "root",
23
- )
24
-
25
- if (!rootGroup) {
26
- console.error("Root group not found")
27
- return
28
- }
29
-
30
- // Process each subgroup under the root
31
- rootGroup.children
32
- .filter((child) => child.name === "g")
33
- .forEach((group, index) => {
34
- const groupId = group.attributes.id
35
- try {
36
- const filePath = `./assets/symbols-svg-json/${groupId}.json`
37
- let groupWithTransformApplied = applyGroupTransformsToChildren(group)
38
-
39
- // Recenter the group (makes it easier to read)
40
- let bounds = getBoundsOfSvgJson(groupWithTransformApplied as any)
41
- groupWithTransformApplied.attributes.transform = toSVG(
42
- compose(
43
- scale(0.1, 0.1),
44
- translate(-bounds.centerX, -bounds.centerY),
45
- ),
46
- )
47
- groupWithTransformApplied = applyGroupTransformsToChildren(
48
- groupWithTransformApplied,
49
- )
50
-
51
- bounds = getBoundsOfSvgJson(groupWithTransformApplied as any)
52
-
53
- const refblocks = convertToObjectWithOrderedPositionIds(
54
- groupWithTransformApplied.children
55
- .filter(
56
- (child) =>
57
- child.name === "circle" &&
58
- (child.attributes["inkscape:label"]?.includes("refblock") ||
59
- child.attributes.id?.includes("refblock")),
60
- )
61
- .map((child) => ({
62
- x: parseFloat(child.attributes.cx),
63
- y: parseFloat(child.attributes.cy),
64
- })),
65
- )
66
-
67
- const textChildren = groupWithTransformApplied.children.filter(
68
- (text) => text.name === "text",
69
- )
70
- const texts = convertToObjectWithOrderedPositionIds(
71
- textChildren.map((text) => ({
72
- type: "text",
73
- text: findInnerText(text),
74
- x: parseFloat(text.attributes.x),
75
- y: parseFloat(text.attributes.y),
76
- })),
77
- )
78
-
79
- const pathChildren = groupWithTransformApplied.children.filter(
80
- (path) => path.name === "path",
81
- )
82
- const paths = Object.fromEntries(
83
- pathChildren.map((path) => [
84
- path.attributes.id!,
85
- {
86
- type: "path",
87
- points: svgPathToPoints(path.attributes.d!),
88
- color: "primary",
89
- fill:
90
- path.attributes.fill === "true" &&
91
- !path.attributes.style?.includes("fill:none"),
92
- },
93
- ]),
94
- )
95
-
96
- const svgData = {
97
- // only for debugging
98
- // svg: groupWithTransformApplied,
99
- paths,
100
- texts,
101
- refblocks,
102
- bounds,
103
- }
104
-
105
- console.log(`Writing to file: ${filePath}`)
106
- fs.writeFileSync(filePath, JSON.stringify(svgData, null, 2))
107
-
108
- if (SOURCE_IGNORE_LIST.includes(groupId)) {
109
- return
110
- }
111
-
112
- // Check if there's a source file for this symbol
113
- const outputPath = `./symbols/${groupId}_horz.ts`
114
- const hasSourceFile = fs.existsSync(outputPath)
115
- const isReadyForGen =
116
- Object.keys(texts).length > 0 &&
117
- Object.keys(paths).length > 0 &&
118
- Object.keys(refblocks).length > 0
119
-
120
- if (!hasSourceFile && !isReadyForGen) {
121
- console.log(
122
- `Skipping ${groupId} because it's not ready for generation (missing some elements)`,
123
- )
124
- console.log(` - texts: ${Object.keys(texts).length}`)
125
- console.log(` - paths: ${Object.keys(paths).length}`)
126
- console.log(` - refblocks: ${Object.keys(refblocks).length}`)
127
- } else if (!hasSourceFile && isReadyForGen) {
128
- console.log(`Creating horz source file: ${outputPath}`)
129
- const content = getTsFileContentForSvgGroup(groupId, svgData as any)
130
- fs.writeFileSync(outputPath, content)
131
- // Write the vert file
132
- const vertOutputPath = `./symbols/${groupId}_vert.ts`
133
- console.log(`Creating vert source file: ${vertOutputPath}`)
134
- const contentVert = `import { rotateSymbol } from "drawing/rotateSymbol"\nimport ${groupId}_horz from "./${groupId}_horz"\n\nexport default rotateSymbol(${groupId}_horz)`
135
- fs.writeFileSync(vertOutputPath, contentVert)
136
- }
137
- } catch (err: any) {
138
- console.log(`Error processing ${groupId}: ${err.message}`)
139
- }
140
- })
141
- } catch (error) {
142
- console.error("Error processing SVG:", error)
143
- }
144
- }
145
-
146
- processSvg()
@@ -1,119 +0,0 @@
1
- import {
2
- fromDefinition,
3
- compose,
4
- applyToPoint,
5
- toString,
6
- type Matrix,
7
- fromTransformAttribute,
8
- identity,
9
- } from "transformation-matrix"
10
- import type { INode } from "svgson"
11
- import { parseSVG, makeAbsolute, type LineToCommand } from "svg-path-parser"
12
- import { serializeSvgPathCommands } from "./serializeSvgPathCommands"
13
-
14
- export function applyGroupTransformsToChildren(group: INode) {
15
- if (!group.attributes.transform) {
16
- return group // No transformation to apply
17
- }
18
-
19
- const groupTransform = parseTransform(group.attributes.transform)
20
-
21
- group.children = group.children
22
- .map((child) => {
23
- const transform = compose(
24
- groupTransform,
25
- parseTransform(child.attributes.transform),
26
- )
27
- delete child.attributes.transform
28
-
29
- if (child.name === "rect") {
30
- // convert to path, it's easier to transform via rotations
31
- return null
32
- child = convertRectToPath(child)
33
- }
34
- if (child.name === "path") {
35
- child.attributes.d = transformPath(child.attributes.d, transform)
36
- const hasFill =
37
- child.attributes.fill && child.attributes.fill !== "none"
38
- child.attributes.fill = hasFill ? "true" : "false"
39
- } else if (child.name === "text") {
40
- const { x, y } = applyToPoint(transform, {
41
- x: parseFloat(child.attributes.x),
42
- y: parseFloat(child.attributes.y),
43
- })
44
- child.attributes.x = x.toString()
45
- child.attributes.y = y.toString()
46
- } else if (child.name === "circle") {
47
- let { cx, cy, r } = child.attributes as any
48
- cx = parseFloat(cx)
49
- cy = parseFloat(cy)
50
- r = parseFloat(r)
51
-
52
- const { x, y } = applyToPoint(transform, { x: cx, y: cy })
53
- r = r * groupTransform.a
54
-
55
- child.attributes.cx = x.toString()
56
- child.attributes.cy = y.toString()
57
- child.attributes.r = r.toString()
58
- } else {
59
- return null
60
- }
61
-
62
- return child
63
- })
64
- .filter((c: INode | null): INode => c as INode) as INode[]
65
-
66
- // Remove the transform from the group since it's now applied to children
67
- delete group.attributes.transform
68
-
69
- return group
70
- }
71
-
72
- function parseTransform(transform: string): Matrix {
73
- if (!transform) return identity()
74
- return compose(fromDefinition(fromTransformAttribute(transform)))
75
- }
76
-
77
- export function transformPath(pathData: string, matrix: Matrix): string {
78
- let parsedPath = parseSVG(pathData)
79
-
80
- parsedPath = makeAbsolute(parsedPath)
81
-
82
- // convert V and H commands to L commands so that rotations can be applied
83
- parsedPath = parsedPath.map((command) => {
84
- const { x0, y0 } = command as any
85
- if (command.code === "V") {
86
- return { code: "L", x: x0, y: command.y } as LineToCommand
87
- } else if (command.code === "H") {
88
- return { code: "L", x: command.x, y: y0 } as LineToCommand
89
- }
90
- return command
91
- })
92
-
93
- const transformedPath = parsedPath.map((command) => {
94
- if ("x" in command && "y" in command) {
95
- const { x, y } = applyToPoint(matrix, { x: command.x, y: command.y })
96
- command.x = x
97
- command.y = y
98
- }
99
- if ("x1" in command && "y1" in command) {
100
- const { x, y } = applyToPoint(matrix, { x: command.x1, y: command.y1 })
101
- command.x1 = x
102
- command.y1 = y
103
- }
104
- if ("x2" in command && "y2" in command) {
105
- const { x, y } = applyToPoint(matrix, { x: command.x2, y: command.y2 })
106
- command.x2 = x
107
- command.y2 = y
108
- }
109
- return command
110
- })
111
-
112
- return serializeSvgPathCommands(transformedPath)
113
- }
114
-
115
- export function convertRectToPath(child: INode): INode {
116
- const { x, y, width, height } = child.attributes as any
117
- // TODO
118
- return null as any
119
- }
@@ -1,11 +0,0 @@
1
- import type { INode } from "svgson"
2
-
3
- export const findInnerText = (node: INode): string => {
4
- if (node.type === "text") {
5
- return node.value
6
- } else if (node.children) {
7
- return node.children.map(findInnerText).join("")
8
- }
9
-
10
- return ""
11
- }
@@ -1,60 +0,0 @@
1
- import { getSvg } from "../../drawing/getSvg"
2
- import symbols from "../../symbols"
3
-
4
- export function generateWebPage(): string {
5
- const symbolEntries = Object.entries(symbols).sort((a, b) =>
6
- a[0].localeCompare(b[0]),
7
- )
8
-
9
- const svgGrid = symbolEntries
10
- .map(([name, symbol]) => {
11
- const svg = getSvg(symbol, { width: 150, height: 150, debug: true })
12
- return `
13
- <div class="symbol-container" style="padding-bottom:28px;">
14
- <div style="font-size: 12px;word-break: break-all; text-align: left;padding-bottom: 16px;">${name}</div>
15
- ${svg}
16
- </div>
17
- `
18
- })
19
- .join("")
20
-
21
- const html = `
22
- <!DOCTYPE html>
23
- <html lang="en">
24
- <head>
25
- <meta charset="UTF-8">
26
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
27
- <title>Schematic Symbols Grid</title>
28
- <style>
29
- body {
30
- font-family: Arial, sans-serif;
31
- margin: 0;
32
- padding: 20px;
33
- }
34
- .grid {
35
- display: grid;
36
- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
37
- gap: 20px;
38
- }
39
- .symbol-container {
40
- border: 1px solid #ccc;
41
- padding: 10px;
42
- text-align: center;
43
- }
44
- svg {
45
- max-width: 100%;
46
- height: auto;
47
- }
48
- </style>
49
- </head>
50
- <body>
51
- <h1>Schematic Symbols</h1>
52
- <div class="grid">
53
- ${svgGrid}
54
- </div>
55
- </body>
56
- </html>
57
- `
58
-
59
- return html
60
- }
@@ -1,33 +0,0 @@
1
- import type { SvgData } from "drawing"
2
-
3
- export const getTsFileContentForSvgGroup = (
4
- groupId: string,
5
- svgData: SvgData,
6
- ) => {
7
- return `
8
- import { defineSymbol } from "drawing/defineSymbol"
9
- import svgJson from "assets/symbols-svg-json/${groupId}.json"
10
-
11
- const { paths, texts, bounds, refblocks } = svgJson
12
-
13
- export default defineSymbol({
14
- primitives: [
15
- ...Object.values(paths),
16
- ${Object.entries(svgData.texts)
17
- .map(([key, text]) => {
18
- return `{ ...texts.${key}, anchor: "middle_left" },`
19
- })
20
- .join("\n")}
21
- ] as any,
22
- ports: [
23
- ${Object.entries(svgData.refblocks)
24
- .map(([key, point], i) => {
25
- return `{ ...refblocks.${key}, labels: ["${i + 1}"] }, // TODO add more "standard" labels`
26
- })
27
- .join("\n")}
28
- ],
29
- size: { width: bounds.width, height: bounds.height },
30
- center: { x: bounds.centerX, y: bounds.centerY },
31
- })
32
- `
33
- }
@@ -1,48 +0,0 @@
1
- import type { Command } from "svg-path-parser"
2
-
3
- export function serializeSvgPathCommands(pathData: Command[]): string {
4
- return pathData
5
- .map((command: Command) => {
6
- let result = command.code
7
-
8
- switch (command.code) {
9
- case "M":
10
- case "m":
11
- case "L":
12
- case "l":
13
- case "T":
14
- case "t":
15
- result += `${command.x},${command.y}`
16
- break
17
- case "H":
18
- case "h":
19
- result += command.x
20
- break
21
- case "V":
22
- case "v":
23
- result += command.y
24
- break
25
- case "C":
26
- case "c":
27
- result += `${command.x1},${command.y1} ${command.x2},${command.y2} ${command.x},${command.y}`
28
- break
29
- case "S":
30
- case "s":
31
- case "Q":
32
- case "q":
33
- // @ts-ignore
34
- result += `${command.x1},${command.y1} ${command.x},${command.y}`
35
- break
36
- case "A":
37
- case "a":
38
- result += `${command.rx},${command.ry} ${command.xAxisRotation} ${command.largeArc ? "1" : "0"},${command.sweep ? "1" : "0"} ${command.x},${command.y}`
39
- break
40
- case "Z":
41
- case "z":
42
- break
43
- }
44
-
45
- return result
46
- })
47
- .join(" ")
48
- }