normaliz.wasm 1.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.
Binary file
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "normaliz.wasm",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "WebAssembly build of Normaliz",
6
+ "exports": {
7
+ ".": "./src/normaliz.js",
8
+ "./dist/normaliz.js": "./dist/normaliz.js"
9
+ },
10
+ "files": [
11
+ "src/",
12
+ "dist/"
13
+ ],
14
+ "scripts": {
15
+ "build": "bash build/build.sh"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/DominikPeters/normaliz.wasm"
20
+ },
21
+ "license": "GPL-3.0-or-later",
22
+ "keywords": [
23
+ "normaliz",
24
+ "wasm",
25
+ "emscripten",
26
+ "polytope",
27
+ "cone",
28
+ "hilbert"
29
+ ]
30
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * normaliz.wasm — JavaScript wrapper for Normaliz WebAssembly module.
3
+ *
4
+ * Usage:
5
+ * import { Normaliz } from 'normaliz.wasm';
6
+ * const nmz = await Normaliz.create();
7
+ * const result = nmz.run('amb_space 2\ncone 2\n1 3\n2 1\n');
8
+ * console.log(result.output); // main .out file contents
9
+ * console.log(result.console); // verbose console log
10
+ * console.log(result.files); // { 'gen': '...', 'ext': '...', ... }
11
+ */
12
+
13
+ import createNormaliz from '../dist/normaliz.js';
14
+
15
+ const OUTPUT_EXTENSIONS = [
16
+ 'out', 'gen', 'egn', 'esp', 'ext', 'typ',
17
+ 'lat', 'cst', 'inv', 'tri', 'ht1', 'dec',
18
+ 'mod', 'msp', 'fac', 'inc', 'tgn',
19
+ ];
20
+
21
+ export class Normaliz {
22
+ /**
23
+ * Create a new Normaliz instance.
24
+ * Each instance holds its own wasm module with a virtual filesystem.
25
+ *
26
+ * @param {Object} [opts]
27
+ * @param {Function} [opts.loadModule] - Custom module loader (overrides default)
28
+ * @param {Function} [opts.onStdout] - Called with each line of stdout during computation
29
+ * @param {Function} [opts.onStderr] - Called with each line of stderr during computation
30
+ * @returns {Promise<Normaliz>}
31
+ */
32
+ static async create(opts = {}) {
33
+ const instance = new Normaliz();
34
+ const loader = opts.loadModule || createNormaliz;
35
+ instance._onStdout = opts.onStdout || null;
36
+ instance._onStderr = opts.onStderr || null;
37
+ instance._module = await loader({
38
+ print: (text) => {
39
+ instance._stdoutBuf.push(text);
40
+ if (instance._onStdout) instance._onStdout(text);
41
+ },
42
+ printErr: (text) => {
43
+ instance._stderrBuf.push(text);
44
+ if (instance._onStderr) instance._onStderr(text);
45
+ },
46
+ });
47
+ return instance;
48
+ }
49
+
50
+ constructor() {
51
+ this._module = null;
52
+ this._stdoutBuf = [];
53
+ this._stderrBuf = [];
54
+ this._onStdout = null;
55
+ this._onStderr = null;
56
+ this._runCounter = 0;
57
+ }
58
+
59
+ /**
60
+ * Run a Normaliz computation.
61
+ *
62
+ * @param {string} input - Contents of the .in file
63
+ * @param {Object} [opts]
64
+ * @param {string[]} [opts.flags] - Extra CLI flags, e.g. ['--verbose', '-a']
65
+ * @returns {{ output: string, console: string, stderr: string, files: Object<string,string>, exitCode: number }}
66
+ */
67
+ run(input, opts = {}) {
68
+ const m = this._module;
69
+ const flags = opts.flags || [];
70
+ const name = `_run${this._runCounter++}`;
71
+ const inFile = `${name}.in`;
72
+
73
+ // Clear buffers
74
+ this._stdoutBuf = [];
75
+ this._stderrBuf = [];
76
+
77
+ // Write input
78
+ m.FS.writeFile(inFile, input);
79
+
80
+ // Run normaliz
81
+ let exitCode = 0;
82
+ try {
83
+ exitCode = m.callMain([...flags, name]);
84
+ } catch (e) {
85
+ // callMain may throw on non-zero exit
86
+ exitCode = 1;
87
+ }
88
+
89
+ // Collect output files
90
+ const files = {};
91
+ for (const ext of OUTPUT_EXTENSIONS) {
92
+ const fname = `${name}.${ext}`;
93
+ try {
94
+ files[ext] = m.FS.readFile(fname, { encoding: 'utf8' });
95
+ } catch (e) {
96
+ // File doesn't exist — computation didn't produce it
97
+ }
98
+ }
99
+
100
+ // Read main output
101
+ const output = files.out || '';
102
+
103
+ // Clean up virtual filesystem
104
+ try { m.FS.unlink(inFile); } catch (e) {}
105
+ for (const ext of OUTPUT_EXTENSIONS) {
106
+ try { m.FS.unlink(`${name}.${ext}`); } catch (e) {}
107
+ }
108
+
109
+ return {
110
+ output,
111
+ console: this._stdoutBuf.join('\n'),
112
+ stderr: this._stderrBuf.join('\n'),
113
+ files,
114
+ exitCode,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * List available example file names.
120
+ * (Requires examples to be loaded via loadExamples first.)
121
+ * @returns {string[]}
122
+ */
123
+ listExamples() {
124
+ try {
125
+ return this._module.FS.readdir('/examples')
126
+ .filter(f => f.endsWith('.in'))
127
+ .sort();
128
+ } catch (e) {
129
+ return [];
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Load example files into the virtual filesystem.
135
+ * @param {Object<string,string>} examples - Map of filename to contents
136
+ */
137
+ loadExamples(examples) {
138
+ const m = this._module;
139
+ try { m.FS.mkdir('/examples'); } catch (e) {}
140
+ for (const [name, content] of Object.entries(examples)) {
141
+ m.FS.writeFile(`/examples/${name}`, content);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Read an example file's contents.
147
+ * @param {string} name - Filename (e.g. '2cone.in')
148
+ * @returns {string}
149
+ */
150
+ readExample(name) {
151
+ return this._module.FS.readFile(`/examples/${name}`, { encoding: 'utf8' });
152
+ }
153
+ }