on master help sign in
Detect errors in port usage (i.e. too many or too few)
commit85bf0921928fef8bfd40bead8c0225c6233ce6b1 authorEvan Czaplicki <info@elm-lang.org> dateMon 6 Jan 2014, 07:49 (13 years ago) parent7e2dece
1 file changed+71−30
runtime/Init.js+71−30
runtime/Init.js+71−30
@@ -10,7 +10,7 @@ Elm.fullscreen = function(module, ports) {
1010 document.head.appendChild(style);
1111 var container = document.createElement('div');
1212 document.body.appendChild(container);
13− return init(ElmRuntime.Display.FULLSCREEN, container, module, ports);
13+ return init(ElmRuntime.Display.FULLSCREEN, container, module, ports || {});
1414};
1515
1616Elm.embed = function(module, container, ports) {
@@ -20,17 +20,37 @@ Elm.embed = function(module, container, ports) {
2020 } else if (container.hasChildNodes()) {
2121 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
2222 }
23− return init(ElmRuntime.Display.COMPONENT, container, module, ports);
23+ return init(ElmRuntime.Display.COMPONENT, container, module, ports || {});
2424};
2525
2626Elm.worker = function(module, ports) {
27− return init(ElmRuntime.Display.NONE, {}, module, ports);
27+ return init(ElmRuntime.Display.NONE, {}, module, ports || {});
2828};
2929
3030Elm.input = function(defaultValue, errorHandler) {
31+ var subscribers = []
32+ function subscribe(handler) {
33+ subscribers.push(handler);
34+ }
35+ function unsubscribe(handler) {
36+ subscribers.pop(subscribers.indexOf(handler));
37+ }
38+ function send(value) {
39+ var len = subscribers.length;
40+ for (var i = 0; i < len; ++i) {
41+ subscribers[i](value);
42+ }
43+ }
44+ return {
45+ send:send,
46+ internal: { defaultValue:defaultValue,
47+ errorHandler:errorHandler,
48+ subscribe: subscribe,
49+ unsubscribe: unsubscribe }
50+ };
3151}
3252
33−function init(display, container, module, moduleToReplace, ports) {
53+function init(display, container, module, ports, moduleToReplace) {
3454 // defining state needed for an instance of the Elm RTS
3555 var inputs = [];
3656
@@ -62,6 +82,10 @@ function init(display, container, module, moduleToReplace, ports) {
6282 listeners.push(listener);
6383 }
6484
85+ var portUses = {}
86+ for (var key in ports) {
87+ portUses[key] = 0;
88+ }
6589 // create the actual RTS. Any impure modules will attach themselves to this
6690 // object. This permits many Elm programs to be embedded per document.
6791 var elm = {
@@ -71,14 +95,13 @@ function init(display, container, module, moduleToReplace, ports) {
7195 id:ElmRuntime.guid(),
7296 addListener:addListener,
7397 inputs:inputs,
74− ports_in:ports,
75− ports_out:{}
98+ ports: { incoming:ports, outgoing:{}, uses:portUses }
7699 };
77100
78101 function swap(newModule) {
79102 removeListeners(listeners);
80103 var div = document.createElement('div');
81− var newElm = init(display, div, newModule, elm);
104+ var newElm = init(display, div, newModule, ports, elm);
82105 inputs = [];
83106 // elm.swap = newElm.swap;
84107 return newElm;
@@ -88,6 +111,7 @@ function init(display, container, module, moduleToReplace, ports) {
88111 var reportAnyErrors = function() {};
89112 try {
90113 Module = module.make(elm);
114+ checkPorts(elm);
91115 } catch(e) {
92116 var directions = "<br/>&nbsp; &nbsp; Open the developer console for more details."
93117 Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
@@ -95,7 +119,7 @@ function init(display, container, module, moduleToReplace, ports) {
95119 }
96120 inputs = ElmRuntime.filterDeadInputs(inputs);
97121 filterListeners(inputs, listeners);
98− addReceivers(elm.ports_out);
122+ addReceivers(elm.ports.outgoing);
99123 if (display !== ElmRuntime.Display.NONE) {
100124 var graphicsNode = initGraphics(elm, Module);
101125 }
@@ -109,9 +133,26 @@ function init(display, container, module, moduleToReplace, ports) {
109133 }
110134
111135 reportAnyErrors();
112− return { swap:swap, ports:elm.ports_out };
136+ return { swap:swap, output:elm.ports.outgoing };
113137};
114138
139+function checkPorts(elm) {
140+ var portUses = elm.ports.uses;
141+ for (var key in portUses) {
142+ var uses = portUses[key]
143+ if (uses === 0) {
144+ throw new Error(
145+ "Initialization Error: there is no port named '" + key + "'.\n" +
146+ "You should probably remove that input from your initialization code.");
147+ } else if (uses > 1) {
148+ throw new Error(
149+ "Initialization Error: port '" + key +
150+ "' has been declared multiple times in the Elm code.\n" +
151+ "Remove declarations until there is exactly one.");
152+ }
153+ }
154+}
155+
115156function filterListeners(inputs, listeners) {
116157 loop:
117158 for (var i = listeners.length; i--; ) {
@@ -134,27 +175,27 @@ function removeListeners(listeners) {
134175
135176// add receivers for built-in ports if they are defined
136177function addReceivers(ports) {
137− if ('log' in ports) {
138− ports.log.subscribe(function(v) { console.log(v) });
139− }
140− if ('stdout' in ports) {
141− var handler = process ? function(v) { process.stdout.write(v); }
142− : function(v) { console.log(v); };
143− ports.stdout.subscribe(handler);
144− }
145− if ('stderr' in ports) {
146− var handler = process ? function(v) { process.stderr.write(v); }
147− : function(v) { console.log('Error:' + v); };
148− ports.stderr.subscribe(handler);
149− }
150− if ('title' in ports) {
151− ports.title.subscribe(function(v) { document.title = v; });
152− }
153− if ('redirect' in ports) {
154− ports.redirect.subscribe(function(v) {
155− if (v.length > 0) window.location = v;
156− });
157− }
178+ if ('log' in ports) {
179+ ports.log.subscribe(function(v) { console.log(v) });
180+ }
181+ if ('stdout' in ports) {
182+ var handler = process ? function(v) { process.stdout.write(v); }
183+ : function(v) { console.log(v); };
184+ ports.stdout.subscribe(handler);
185+ }
186+ if ('stderr' in ports) {
187+ var handler = process ? function(v) { process.stderr.write(v); }
188+ : function(v) { console.log('Error:' + v); };
189+ ports.stderr.subscribe(handler);
190+ }
191+ if ('title' in ports) {
192+ ports.title.subscribe(function(v) { document.title = v; });
193+ }
194+ if ('redirect' in ports) {
195+ ports.redirect.subscribe(function(v) {
196+ if (v.length > 0) window.location = v;
197+ });
198+ }
158199}
159200
160201function initGraphics(elm, Module) {