@rulecad/variables 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@rulecad/variables",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Design values you can trace: every number says where it comes from, and expressions are parsed, never run.",
5
5
  "type": "module",
6
- "exports": "./variables.mjs",
6
+ "exports": {
7
+ "types": "./variables.d.mts",
8
+ "default": "./variables.mjs"
9
+ },
7
10
  "files": [
8
11
  "variables.mjs",
12
+ "variables.d.mts",
9
13
  "README.md",
10
14
  "LICENSE"
11
15
  ],
@@ -28,5 +32,6 @@
28
32
  },
29
33
  "scripts": {
30
34
  "test": "node --test"
31
- }
35
+ },
36
+ "types": "./variables.d.mts"
32
37
  }
@@ -0,0 +1,73 @@
1
+ export function checkName(name: any, d: any, v: any): string;
2
+ /**
3
+ * One expression: + - * / and brackets, min, max, round, sind, cosd, tand, over numbers and names. Never runs code.
4
+ * @param {string | number} src
5
+ * @param {(name: string) => number} lookup the value of a name
6
+ * @returns {number}
7
+ */
8
+ export function evaluate(src: string | number, lookup: (name: string) => number): number;
9
+ /**
10
+ * Every variable's value, and an entry for each variable and rule for checks and rule cards.
11
+ * @param {DesignObject} object
12
+ * @param {{ sets?: Record<string, RuleSet>, set?: Record<string, number | string>, display?: Record<string, number | string>, load?: (name: string) => RuleSet }} [options]
13
+ * @returns {{ values: Record<string, any>, entries: Entry[] }}
14
+ */
15
+ export function resolve(object: DesignObject, { sets, set, display, load }?: {
16
+ sets?: Record<string, RuleSet>;
17
+ set?: Record<string, number | string>;
18
+ display?: Record<string, number | string>;
19
+ load?: (name: string) => RuleSet;
20
+ }): {
21
+ values: Record<string, any>;
22
+ entries: Entry[];
23
+ };
24
+ /**
25
+ * Number literals in a design's code other than 0, 1 and 2 (outside comments and strings).
26
+ * @param {string} source
27
+ * @returns {{ line: number, text: string }[]}
28
+ */
29
+ export function lint(source: string): {
30
+ line: number;
31
+ text: string;
32
+ }[];
33
+ /** @typedef {{ value: number | string, unit?: string, rule?: string, kind?: 'spec' | 'community' | 'default' | 'estimate' | 'measured', source?: string, checked?: string, label?: string, show?: boolean, interface?: boolean, tweak?: { min: number, max: number }, choice?: string[], type?: 'text' | 'anchor' | 'layout' }} Variable */
34
+ /** @typedef {{ name?: string, rules: Record<string, Variable> }} RuleSet */
35
+ /** @typedef {{ uses?: string[], variables?: Record<string, Variable>, [field: string]: any }} DesignObject */
36
+ /** @typedef {{ name: string, value: number | string, used?: boolean, set?: boolean, [field: string]: any }} Entry */
37
+ export const ANCHORS: string[];
38
+ export function isName(d: any): boolean;
39
+ export function options(d: any): any;
40
+ export function fmt(n: number | string): string;
41
+ export type Variable = {
42
+ value: number | string;
43
+ unit?: string;
44
+ rule?: string;
45
+ kind?: "spec" | "community" | "default" | "estimate" | "measured";
46
+ source?: string;
47
+ checked?: string;
48
+ label?: string;
49
+ show?: boolean;
50
+ interface?: boolean;
51
+ tweak?: {
52
+ min: number;
53
+ max: number;
54
+ };
55
+ choice?: string[];
56
+ type?: "text" | "anchor" | "layout";
57
+ };
58
+ export type RuleSet = {
59
+ name?: string;
60
+ rules: Record<string, Variable>;
61
+ };
62
+ export type DesignObject = {
63
+ uses?: string[];
64
+ variables?: Record<string, Variable>;
65
+ [field: string]: any;
66
+ };
67
+ export type Entry = {
68
+ name: string;
69
+ value: number | string;
70
+ used?: boolean;
71
+ set?: boolean;
72
+ [field: string]: any;
73
+ };
package/variables.mjs CHANGED
@@ -7,6 +7,11 @@
7
7
  // No imports and no file access: it runs in a browser as well. Rule sets are handed in (sets) or fetched by name
8
8
  // through load(name), such as one that reads rules/<name>.json.
9
9
 
10
+ /** @typedef {{ value: number | string, unit?: string, rule?: string, kind?: 'spec' | 'community' | 'default' | 'estimate' | 'measured', source?: string, checked?: string, label?: string, show?: boolean, interface?: boolean, tweak?: { min: number, max: number }, choice?: string[], type?: 'text' | 'anchor' | 'layout' }} Variable */
11
+ /** @typedef {{ name?: string, rules: Record<string, Variable> }} RuleSet */
12
+ /** @typedef {{ uses?: string[], variables?: Record<string, Variable>, [field: string]: any }} DesignObject */
13
+ /** @typedef {{ name: string, value: number | string, used?: boolean, set?: boolean, [field: string]: any }} Entry */
14
+
10
15
  export const ANCHORS = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'];
11
16
  // A variable that holds a name or text, and the names it may hold (null: any text)
12
17
  export const isName = (d) => !!(d.choice || ['text', 'anchor', 'layout'].includes(d.type));
@@ -35,6 +40,12 @@ function tokens(src) {
35
40
  }
36
41
 
37
42
  // evaluate("line * 3", lookup) -> number. lookup(name) gives a name's value.
43
+ /**
44
+ * One expression: + - * / and brackets, min, max, round, sind, cosd, tand, over numbers and names. Never runs code.
45
+ * @param {string | number} src
46
+ * @param {(name: string) => number} lookup the value of a name
47
+ * @returns {number}
48
+ */
38
49
  export function evaluate(src, lookup) {
39
50
  if (typeof src === 'number') return src;
40
51
  const t = tokens(String(src));
@@ -79,6 +90,12 @@ export function evaluate(src, lookup) {
79
90
  // { "type": "text", "value": "", "max": 8 } free text, e.g. a keycap's legend
80
91
  // { "type": "anchor", "value": "mc" } one of 9 places on a face: tl tc tr, ml mc mr, bl bc br
81
92
  // { "type": "layout", "value": "grid", "choice": [...] } a layout file in the project's layouts/ (or a built-in)
93
+ /**
94
+ * Every variable's value, and an entry for each variable and rule for checks and rule cards.
95
+ * @param {DesignObject} object
96
+ * @param {{ sets?: Record<string, RuleSet>, set?: Record<string, number | string>, display?: Record<string, number | string>, load?: (name: string) => RuleSet }} [options]
97
+ * @returns {{ values: Record<string, any>, entries: Entry[] }}
98
+ */
82
99
  export function resolve(object, { sets = {}, set = {}, display = {}, load } = {}) {
83
100
  const ruleSets = Object.fromEntries((object.uses || []).map((u) => {
84
101
  const s = sets[u] || (load ? load(u) : null);
@@ -134,10 +151,16 @@ export function resolve(object, { sets = {}, set = {}, display = {}, load } = {}
134
151
  }
135
152
 
136
153
  // Round for display: at most 2 decimals, no trailing zeros.
154
+ /** A number to two decimals at most; a name as it is. @param {number | string} n @returns {string} */
137
155
  export const fmt = (n) => (typeof n === 'number' ? String(Number(n.toFixed(2))) : String(n)); // choices are names
138
156
 
139
157
  // lint(source) -> [{ line, text }]: number literals in a design's code that should be variables. Every measurement
140
158
  // belongs in a variable that says where it comes from; only 0, 1 and 2 (and numbers in comments and strings) pass.
159
+ /**
160
+ * Number literals in a design's code other than 0, 1 and 2 (outside comments and strings).
161
+ * @param {string} source
162
+ * @returns {{ line: number, text: string }[]}
163
+ */
141
164
  export function lint(source) {
142
165
  const code = source.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' ')).replace(/\/\/.*$/gm, '')
143
166
  .replace(/(['"`])(?:\\.|(?!\1).)*\1/g, (m) => m.replace(/./g, ' '));