spade 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile.lock +4 -3
- data/examples/todos/lib/main.js +4 -3
- data/lib/node/loader.js +11 -10
- data/lib/node/sandbox.js +10 -0
- data/lib/spade.js +217 -180
- data/lib/spade.rb +1 -1
- data/lib/spade/bundle.rb +29 -34
- data/lib/spade/cli.rb +1 -0
- data/lib/spade/cli/base.rb +9 -0
- data/lib/spade/cli/project_generator.rb +58 -0
- data/lib/spade/context.rb +2 -2
- data/lib/spade/loader.rb +0 -5
- data/lib/spade/local.rb +4 -11
- data/lib/spade/server.rb +1 -0
- data/lib/spade/templates/project/LICENSE +19 -0
- data/lib/spade/templates/project/README.md +21 -0
- data/lib/spade/templates/project/lib/main.js +9 -0
- data/lib/spade/templates/project/project.json +31 -0
- data/lib/spade/templates/project/tests/main-test.js +8 -0
- data/lib/spade/version.rb +1 -1
- data/package.json +1 -1
- data/spec/cli/new_spec.rb +5 -0
- data/spec/javascript/require-test.js +69 -10
- metadata +10 -2
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
spade (0.0.
|
4
|
+
spade (0.0.7)
|
5
|
+
childlabor (~> 0.0.3)
|
5
6
|
eventmachine (~> 0.12.10)
|
6
7
|
gemcutter (~> 0.6.1)
|
7
8
|
highline (~> 1.6.1)
|
@@ -13,6 +14,7 @@ PATH
|
|
13
14
|
GEM
|
14
15
|
remote: http://rubygems.org/
|
15
16
|
specs:
|
17
|
+
childlabor (0.0.3)
|
16
18
|
diff-lcs (1.1.2)
|
17
19
|
eventmachine (0.12.10)
|
18
20
|
gemcutter (0.6.1)
|
@@ -27,11 +29,10 @@ GEM
|
|
27
29
|
rspec-expectations (2.5.0)
|
28
30
|
diff-lcs (~> 1.1.2)
|
29
31
|
rspec-mocks (2.5.0)
|
30
|
-
therubyracer (0.8.
|
32
|
+
therubyracer (0.8.1)
|
31
33
|
thor (0.14.6)
|
32
34
|
|
33
35
|
PLATFORMS
|
34
|
-
java
|
35
36
|
ruby
|
36
37
|
|
37
38
|
DEPENDENCIES
|
data/examples/todos/lib/main.js
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require('sproutcore-corefoundation');
|
2
2
|
|
3
3
|
// Remove loading text
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
$(document.body).html('');
|
5
|
+
|
6
|
+
// Trigger onReady handler
|
7
|
+
SC.onReady.done();
|
7
8
|
|
8
9
|
require('./todos');
|
9
10
|
require('./~resources/templates/todos');
|
data/lib/node/loader.js
CHANGED
@@ -7,7 +7,8 @@
|
|
7
7
|
|
8
8
|
var PATH = require('path'),
|
9
9
|
SYS = require('sys'),
|
10
|
-
FS = require('fs')
|
10
|
+
FS = require('fs'),
|
11
|
+
SPADE_DIR = '.spade'; // Would be nice if we could share Spade::SPADE_DIR
|
11
12
|
|
12
13
|
exports.Loader = function() {
|
13
14
|
this.root = process.cwd();
|
@@ -70,18 +71,19 @@ Lp.packages = function() {
|
|
70
71
|
if (this._packages) return this._packages;
|
71
72
|
var packages = {};
|
72
73
|
this._packages = packages;
|
73
|
-
|
74
|
-
// add
|
75
|
-
var
|
76
|
-
if (PATH.existsSync(
|
77
|
-
FS.readdirSync(
|
78
|
-
addPackage(packages,
|
74
|
+
|
75
|
+
// add spade install dir
|
76
|
+
var spadeDir = PATH.join(process.env.HOME, SPADE_DIR, 'gems');
|
77
|
+
if (PATH.existsSync(spadeDir) && FS.statSync(spadeDir).isDirectory()) {
|
78
|
+
FS.readdirSync(spadeDir).forEach(function(name){
|
79
|
+
addPackage(packages, spadeDir, name);
|
79
80
|
});
|
80
81
|
}
|
81
|
-
|
82
|
+
|
83
|
+
// Add other dirs in reverse order of precedence
|
82
84
|
var dirs = ['.spade/packages', 'node_modules', '.node_modules', 'vendor/cache', 'vendor/packages', 'packages'];
|
83
85
|
var rootdir = PATH.normalize(this.root);
|
84
|
-
|
86
|
+
|
85
87
|
dirs.forEach(function(dirname) {
|
86
88
|
dirname = dirname.split('/');
|
87
89
|
dirname.unshift(rootdir);
|
@@ -98,7 +100,6 @@ Lp.packages = function() {
|
|
98
100
|
return packages;
|
99
101
|
};
|
100
102
|
|
101
|
-
// FIXME: This should check to see if the package is already loaded before loading again
|
102
103
|
Lp.loadFactory = function(spade, id, formats, done) {
|
103
104
|
if (!formats) { formats = []; }
|
104
105
|
if (formats.length === 0) { formats.push('js'); }
|
data/lib/node/sandbox.js
CHANGED
@@ -31,4 +31,14 @@ Sandbox.prototype.compile = function(code, filename) {
|
|
31
31
|
return VM.runInContext(code, this.ctx, filename || '(unknown)');
|
32
32
|
};
|
33
33
|
|
34
|
+
Sandbox.prototype.globals = function() {
|
35
|
+
var output = {};
|
36
|
+
for (var name in this.ctx){
|
37
|
+
if (this.ctx.hasOwnProperty(name)) {
|
38
|
+
output[name] = this.ctx[name];
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return output;
|
42
|
+
};
|
43
|
+
|
34
44
|
exports.Sandbox = Sandbox;
|
data/lib/spade.js
CHANGED
@@ -11,22 +11,22 @@
|
|
11
11
|
Spade 2.0 CommonJS Runtime
|
12
12
|
copyright 2010 Strobe Inc.
|
13
13
|
|
14
|
-
Permission is hereby granted, free of charge, to any person obtaining a
|
15
|
-
copy of this software and associated documentation files (the "Software"),
|
16
|
-
to deal in the Software without restriction, including without limitation
|
17
|
-
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
18
|
-
and/or sell copies of the Software, and to permit persons to whom the
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
15
|
+
copy of this software and associated documentation files (the "Software"),
|
16
|
+
to deal in the Software without restriction, including without limitation
|
17
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
18
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
19
19
|
Software is furnished to do so, subject to the following conditions:
|
20
20
|
|
21
|
-
The above copyright notice and this permission notice shall be included in
|
21
|
+
The above copyright notice and this permission notice shall be included in
|
22
22
|
all copies or substantial portions of the Software.
|
23
23
|
|
24
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
29
|
-
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
29
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
30
30
|
DEALINGS IN THE SOFTWARE.
|
31
31
|
|
32
32
|
Spade is part of the SproutCore project.
|
@@ -41,31 +41,31 @@ For more information visit http://www.sproutcore.com/spade
|
|
41
41
|
// Make this work when loaded from browser or from node.js
|
42
42
|
var spade ;
|
43
43
|
(function() {
|
44
|
-
|
45
|
-
var Spade, Tp, Sandbox, Sp,
|
44
|
+
|
45
|
+
var Spade, Tp, Sandbox, Sp,
|
46
46
|
Loader, Lp, K, Compiler, Cp;
|
47
|
-
|
47
|
+
|
48
48
|
// defining these types here will allow the minifier the compact them
|
49
49
|
if ('undefined' !== typeof spade) return ; // nothing to do
|
50
|
-
|
50
|
+
|
51
51
|
K = function() {}; // noop
|
52
52
|
|
53
53
|
// assume id is already normalized
|
54
54
|
function packageIdFor(normalizedId) {
|
55
55
|
return normalizedId.slice(0, normalizedId.indexOf('/'));
|
56
56
|
}
|
57
|
-
|
57
|
+
|
58
58
|
function remap(id, contextPkg) {
|
59
59
|
var mappings = contextPkg ? contextPkg.mappings : null;
|
60
60
|
if (!mappings) return id;
|
61
|
-
|
61
|
+
|
62
62
|
var packageId = packageIdFor(id);
|
63
63
|
if (mappings[packageId]) {
|
64
64
|
id = mappings[packageId] + id.slice(id.indexOf('/'));
|
65
65
|
}
|
66
66
|
return id;
|
67
67
|
}
|
68
|
-
|
68
|
+
|
69
69
|
function normalize(id, contextId, contextPkg, _asPackage) {
|
70
70
|
// slice separator off the end since it is not used...
|
71
71
|
if (id[id.length-1]==='/') id = id.slice(0,-1);
|
@@ -104,7 +104,7 @@ var spade ;
|
|
104
104
|
|
105
105
|
// else, just slice off beginning '/' if needed
|
106
106
|
} else if (id[0]==='/') id = id.slice(1);
|
107
|
-
|
107
|
+
|
108
108
|
// if we end up with no separators, make this a pkg
|
109
109
|
if (id.indexOf('/')<0) id = id+(_asPackage ? '/~package' : '/main');
|
110
110
|
// may need to walk if there is a separator...
|
@@ -122,9 +122,25 @@ var spade ;
|
|
122
122
|
return remap(id, contextPkg);
|
123
123
|
}
|
124
124
|
|
125
|
+
function parseIdFormats(id, formats) {
|
126
|
+
// Handle requires with extension
|
127
|
+
var formatRE = new RegExp("^(.+)\\.("+formats.join('|')+")$"), match, format;
|
128
|
+
if (id.substring(0,5) !== "file:" && (match = id.match(formatRE))) {
|
129
|
+
id = match[1];
|
130
|
+
format = match[2];
|
131
|
+
formats = [format];
|
132
|
+
}
|
133
|
+
|
134
|
+
return {
|
135
|
+
id: id,
|
136
|
+
format: format,
|
137
|
+
formats: formats
|
138
|
+
};
|
139
|
+
}
|
140
|
+
|
125
141
|
// ..........................................................
|
126
142
|
// PLATFORM
|
127
|
-
//
|
143
|
+
//
|
128
144
|
// Detect important platform properties. Mostly for determining code
|
129
145
|
// that can't run one way or the other.
|
130
146
|
var SPADE_PLATFORM;
|
@@ -133,50 +149,51 @@ var spade ;
|
|
133
149
|
} else {
|
134
150
|
SPADE_PLATFORM = ENV.SPADE_PLATFORM;
|
135
151
|
}
|
136
|
-
|
152
|
+
|
137
153
|
var LANG;
|
138
154
|
if ('undefined'!==typeof ENV) LANG = ENV.LANG;
|
139
155
|
if (!LANG && 'undefined'!==typeof navigator) LANG = navigator.language;
|
140
156
|
if (!LANG) LANG = 'en-US';
|
141
|
-
|
157
|
+
|
142
158
|
|
143
159
|
// ..........................................................
|
144
160
|
// Sandbox - you could make a secure version if you want...
|
145
|
-
//
|
146
|
-
|
161
|
+
//
|
162
|
+
|
147
163
|
// runs a factory within context and returns exports...
|
148
164
|
function execFactory(id, factory, sandbox, spade) {
|
149
165
|
var require, mod;
|
150
|
-
|
166
|
+
|
151
167
|
var pkg = spade.package(id),
|
152
168
|
filename = factory.filename,
|
153
169
|
format = factory.format,
|
154
170
|
ARGV = sandbox.ARGV,
|
155
|
-
ENV = sandbox.ENV
|
156
|
-
|
171
|
+
ENV = sandbox.ENV,
|
172
|
+
fullId = id+'.'+format;
|
173
|
+
|
157
174
|
require = function(moduleId) {
|
158
175
|
return sandbox.require(moduleId, id, pkg);
|
159
176
|
};
|
160
177
|
|
161
178
|
// make the require 'object' have the same API as sandbox and spade.
|
162
179
|
require.require = require;
|
163
|
-
|
180
|
+
|
164
181
|
require.exists = function(moduleId) {
|
165
|
-
return sandbox.exists(normalize(moduleId, id, pkg));
|
182
|
+
return sandbox.exists(normalize(moduleId, id, pkg));
|
166
183
|
};
|
167
|
-
|
184
|
+
|
168
185
|
require.normalize = function(moduleId) {
|
169
186
|
return normalize(moduleId, id, pkg);
|
170
187
|
};
|
171
|
-
|
188
|
+
|
172
189
|
require.async = function(moduleId, callback) {
|
173
190
|
return sandbox.async(normalize(moduleId, id, pkg), callback);
|
174
191
|
};
|
175
|
-
|
192
|
+
|
176
193
|
require.sandbox = function(name, isolate) {
|
177
194
|
return spade.sandbox(name, isolate);
|
178
195
|
};
|
179
|
-
|
196
|
+
|
180
197
|
require.url = function(moduleId, ext) {
|
181
198
|
return sandbox.url(normalize(moduleId, id, pkg), ext);
|
182
199
|
};
|
@@ -186,26 +203,26 @@ var spade ;
|
|
186
203
|
};
|
187
204
|
|
188
205
|
require.id = id; // so you can tell one require from another
|
189
|
-
|
190
|
-
sandbox._modules[id] = mod = {
|
191
|
-
id: id,
|
192
|
-
exports: {},
|
193
|
-
sandbox: sandbox
|
206
|
+
|
207
|
+
sandbox._modules[id] = mod = {
|
208
|
+
id: id,
|
209
|
+
exports: {},
|
210
|
+
sandbox: sandbox
|
194
211
|
};
|
195
|
-
|
212
|
+
|
196
213
|
factory = factory.data; // extract the raw module body
|
197
|
-
|
214
|
+
|
198
215
|
// compile if needed - use cache so we only do it once per sandbox
|
199
216
|
if ('string' === typeof factory) {
|
200
|
-
if (sandbox._factories[
|
201
|
-
factory = sandbox._factories[
|
217
|
+
if (sandbox._factories[fullId]) {
|
218
|
+
factory = sandbox._factories[fullId];
|
202
219
|
} else {
|
203
|
-
sandbox._loading[id] = true;
|
220
|
+
sandbox._loading[id] = sandbox._loading[fullId] = true;
|
204
221
|
factory = sandbox.compileFormat(factory, filename, format, pkg);
|
205
222
|
factory = sandbox.compilePreprocessors(factory, filename, pkg, id);
|
206
223
|
factory = sandbox.compile('(function(require, exports, __module, ARGV, ENV, __filename) {'+factory+';\n}) //@ sourceURL='+filename+'\n', filename);
|
207
|
-
sandbox._factories[
|
208
|
-
sandbox._loading[id] = false;
|
224
|
+
sandbox._factories[fullId] = factory;
|
225
|
+
sandbox._loading[id] = sandbox._loading[fullId] = false;
|
209
226
|
}
|
210
227
|
}
|
211
228
|
|
@@ -218,29 +235,29 @@ var spade ;
|
|
218
235
|
|
219
236
|
return mod.exports;
|
220
237
|
}
|
221
|
-
|
238
|
+
|
222
239
|
/**
|
223
240
|
@constructor
|
224
|
-
|
241
|
+
|
225
242
|
Sandbox provides an isolated context for loading and running modules.
|
226
|
-
You can create new sandboxes anytime you want. If you pass true for the
|
227
|
-
isolate flag, then the sandbox will be created in a separate context if
|
228
|
-
supported on the platform. Otherwise it will share globals with the
|
243
|
+
You can create new sandboxes anytime you want. If you pass true for the
|
244
|
+
isolate flag, then the sandbox will be created in a separate context if
|
245
|
+
supported on the platform. Otherwise it will share globals with the
|
229
246
|
default sandbox context.
|
230
|
-
|
231
|
-
Note that isolated sandboxes are not the same as secure sandboxes. For
|
232
|
-
example in the browser, a isolated sandbox is created using an iframe
|
233
|
-
which still exposes access to the DOM and parent environment.
|
234
|
-
|
247
|
+
|
248
|
+
Note that isolated sandboxes are not the same as secure sandboxes. For
|
249
|
+
example in the browser, a isolated sandbox is created using an iframe
|
250
|
+
which still exposes access to the DOM and parent environment.
|
251
|
+
|
235
252
|
Isolated sandboxes are mostly useful for testing and sharing plugin code
|
236
253
|
that might want to use different versions of packages.
|
237
|
-
|
254
|
+
|
238
255
|
@param {Spade} spade
|
239
256
|
The spade instance
|
240
|
-
|
257
|
+
|
241
258
|
@param {Boolean} isolate
|
242
259
|
Set to true if you want to isolate it
|
243
|
-
|
260
|
+
|
244
261
|
@returns {Sandbox} instance
|
245
262
|
*/
|
246
263
|
Sandbox = function(spade, name, isolate) {
|
@@ -248,10 +265,10 @@ var spade ;
|
|
248
265
|
isolate = name;
|
249
266
|
name = null;
|
250
267
|
}
|
251
|
-
|
268
|
+
|
252
269
|
if (!name) name = '(anonymous)';
|
253
|
-
|
254
|
-
this.spade = spade;
|
270
|
+
|
271
|
+
this.spade = spade;
|
255
272
|
this.name = name;
|
256
273
|
this.isIsolated = !!isolate;
|
257
274
|
this._factories = {}; // compiled factories
|
@@ -262,14 +279,14 @@ var spade ;
|
|
262
279
|
|
263
280
|
// alias this to help minifier make the page a big smaller.
|
264
281
|
Sp = Sandbox.prototype;
|
265
|
-
|
282
|
+
|
266
283
|
Sp.toString = function() {
|
267
284
|
return '[Sandbox '+this.name+']';
|
268
285
|
};
|
269
286
|
|
270
287
|
/**
|
271
288
|
Evaluate the passed string in the Sandbox context, returning the result.
|
272
|
-
This is the primitive used to compile string-encoded factories into
|
289
|
+
This is the primitive used to compile string-encoded factories into
|
273
290
|
modules that can execute within a specific context.
|
274
291
|
*/
|
275
292
|
Sp.compile = function(code, filename) {
|
@@ -344,7 +361,7 @@ var spade ;
|
|
344
361
|
|
345
362
|
var ret = this._modules[id];
|
346
363
|
if (ret) ret = ret.exports;
|
347
|
-
|
364
|
+
|
348
365
|
if (ret) {
|
349
366
|
if (!this._used[id]) this._used[id] = ret;
|
350
367
|
return ret ;
|
@@ -356,9 +373,9 @@ var spade ;
|
|
356
373
|
var spade = this.spade;
|
357
374
|
if (!this.ENV) this.ENV = spade.env(); // get at the last minute
|
358
375
|
if (!this.ARGV) this.ARGV = spade.argv();
|
359
|
-
|
376
|
+
|
360
377
|
ret = execFactory(id, factory, this, spade);
|
361
|
-
|
378
|
+
|
362
379
|
// detect circular references...
|
363
380
|
if (this._used[id] && (this._used[id] !== ret)) {
|
364
381
|
throw new Error("Circular require detected for module "+id);
|
@@ -378,34 +395,34 @@ var spade ;
|
|
378
395
|
var pkg = callingId ? this.spade.package(callingId) : null;
|
379
396
|
id = normalize(id, callingId, pkg);
|
380
397
|
if (this._modules[id]) return true;
|
381
|
-
return this.spade.factoryExists(this.spade.resolve(id, this));
|
398
|
+
return this.spade.factoryExists(this.spade.resolve(id, this));
|
382
399
|
};
|
383
|
-
|
400
|
+
|
384
401
|
/**
|
385
402
|
Sandbox-specific async load. This is actually the most primitive form of
|
386
403
|
require.
|
387
404
|
*/
|
388
405
|
Sp.async = function(id, callback, callingId) {
|
389
406
|
var spade = this.spade, pkg;
|
390
|
-
|
407
|
+
|
391
408
|
pkg = callingId ? this.spade.package(callingId) : null;
|
392
409
|
id = spade.resolve(normalize(id, callingId, pkg), this);
|
393
410
|
return spade.loadFactory(id, callback);
|
394
411
|
};
|
395
|
-
|
412
|
+
|
396
413
|
Sp.url = function(id, ext, callingId) {
|
397
|
-
var ret, pkg;
|
398
|
-
|
414
|
+
var ret, pkg;
|
415
|
+
|
399
416
|
pkg = callingId ? this.spade.package(callingId) : null;
|
400
417
|
id = normalize(id, callingId, pkg);
|
401
|
-
|
402
|
-
pkg = this.spade.package(id);
|
418
|
+
|
419
|
+
pkg = this.spade.package(id);
|
403
420
|
if (!pkg) {
|
404
421
|
var packageId = packageIdFor(id)+'/~package';
|
405
422
|
if (this.spade.exists(packageId)) this.spade.require(packageId);
|
406
423
|
pkg = this.spade.package(id);
|
407
424
|
}
|
408
|
-
|
425
|
+
|
409
426
|
if (!pkg) {
|
410
427
|
throw new Error("Can't get url for non-existent package "+id);
|
411
428
|
}
|
@@ -413,7 +430,7 @@ var spade ;
|
|
413
430
|
if (!pkg.root) {
|
414
431
|
throw new Error('Package for '+id+' does not support urls');
|
415
432
|
}
|
416
|
-
|
433
|
+
|
417
434
|
ret = pkg.root + id.slice(id.indexOf('/'));
|
418
435
|
if (ext) ret = ret+'.'+ext;
|
419
436
|
return ret ;
|
@@ -452,7 +469,7 @@ var spade ;
|
|
452
469
|
};
|
453
470
|
|
454
471
|
Sp.isDestroyed = false;
|
455
|
-
|
472
|
+
|
456
473
|
Sp.destroy = function() {
|
457
474
|
if (!this.isDestroyed) {
|
458
475
|
this.isDestroyed = true;
|
@@ -460,16 +477,16 @@ var spade ;
|
|
460
477
|
}
|
461
478
|
return this;
|
462
479
|
};
|
463
|
-
|
480
|
+
|
464
481
|
// ..........................................................
|
465
482
|
// LOADER
|
466
|
-
//
|
467
|
-
|
483
|
+
//
|
484
|
+
|
468
485
|
/**
|
469
486
|
The built-in loader object knows how to load whole packages as long as
|
470
487
|
you have registered an external reference to the package. This is pkg
|
471
488
|
info that contains:
|
472
|
-
|
489
|
+
|
473
490
|
{
|
474
491
|
extern: true, // this is not a real package yet
|
475
492
|
src: 'http://example.com/bar', // URL to load
|
@@ -479,12 +496,12 @@ var spade ;
|
|
479
496
|
Loader = function() {
|
480
497
|
this._loading = {};
|
481
498
|
};
|
482
|
-
|
499
|
+
|
483
500
|
Lp = Loader.prototype;
|
484
501
|
|
485
502
|
function syncLoad(spade, id, url, format, force) {
|
486
503
|
if (force) url = url+'?'+Date.now();
|
487
|
-
|
504
|
+
|
488
505
|
var xhr = new XMLHttpRequest();
|
489
506
|
xhr.open('GET', url, false);
|
490
507
|
try {
|
@@ -590,21 +607,21 @@ var spade ;
|
|
590
607
|
if ('undefined'===typeof document) {
|
591
608
|
var err = new Error("Cannot load package "+id+" outside of browser");
|
592
609
|
if (done) done(err);
|
593
|
-
else throw err;
|
610
|
+
else throw err;
|
594
611
|
return false;
|
595
612
|
}
|
596
|
-
|
613
|
+
|
597
614
|
return true;
|
598
615
|
}
|
599
|
-
|
616
|
+
|
600
617
|
Lp.loadFactory = function(spade, id, formats, done) {
|
601
618
|
|
602
|
-
var url, loaded, packageId,
|
619
|
+
var url, loaded, packageId,
|
603
620
|
extern = spade.package(id), that = this;
|
604
621
|
|
605
622
|
// loader only works for sync requests if the package info permits sync
|
606
623
|
// loading. In production mode, normally it should not.
|
607
|
-
if (!done && (!extern || !extern.sync)) return this;
|
624
|
+
if (!done && (!extern || !extern.sync)) return this;
|
608
625
|
|
609
626
|
// this loader only works in the browser
|
610
627
|
if (!verifyInBrowser(id, done)) return this;
|
@@ -617,14 +634,14 @@ var spade ;
|
|
617
634
|
// not actually loadable
|
618
635
|
} else if (!extern || !extern.extern) {
|
619
636
|
done(new Error('Module '+id+' not found'));
|
620
|
-
|
637
|
+
|
621
638
|
} else {
|
622
639
|
|
623
640
|
// now do actual load of src
|
624
641
|
if (!extern.src) {
|
625
642
|
throw new Error("Cannot load package "+id+" without a src URL");
|
626
643
|
}
|
627
|
-
|
644
|
+
|
628
645
|
// if already loading, just add to queue
|
629
646
|
packageId = packageIdFor(normalize(id));
|
630
647
|
if (this._loading[packageId]) {
|
@@ -634,34 +651,34 @@ var spade ;
|
|
634
651
|
this.loadURL(extern.src, function() { that.didLoad(packageId); });
|
635
652
|
// TODO: Load dependencies
|
636
653
|
}
|
637
|
-
}
|
654
|
+
}
|
638
655
|
return this;
|
639
656
|
};
|
640
657
|
|
641
658
|
Lp.exists = function(spade, id, formats) {
|
642
659
|
|
643
660
|
var extern = spade.package(id);
|
644
|
-
|
661
|
+
|
645
662
|
// loader only works for sync requests if the package info permits sync
|
646
663
|
// loading. In production mode, normally it should not.
|
647
|
-
if (!extern || !extern.sync || !extern.root) return false;
|
664
|
+
if (!extern || !extern.sync || !extern.root) return false;
|
648
665
|
|
649
666
|
// this loader only works in the browser
|
650
667
|
if (!verifyInBrowser(id)) return false;
|
651
668
|
return syncLoadFormats(spade, id, extern, formats, true);
|
652
669
|
};
|
653
|
-
|
670
|
+
|
654
671
|
Lp.didLoad = function(packageId) {
|
655
672
|
// TODO: verify/load dependencies
|
656
673
|
var callbacks = this._loading[packageId];
|
657
674
|
delete this._loading[packageId];
|
658
675
|
if (callbacks) callbacks.forEach(function(done) { done(); });
|
659
676
|
};
|
660
|
-
|
677
|
+
|
661
678
|
// actually create a script tag and load it
|
662
679
|
Lp.loadURL = function(url, callback) {
|
663
680
|
var el, head;
|
664
|
-
|
681
|
+
|
665
682
|
el = document.createElement('script');
|
666
683
|
el.src = url;
|
667
684
|
el.type = 'text/javascript';
|
@@ -681,7 +698,7 @@ var spade ;
|
|
681
698
|
if ( document.readyState === "complete" ) return setTimeout(callback, 1);
|
682
699
|
|
683
700
|
var handler, handled = false;
|
684
|
-
|
701
|
+
|
685
702
|
// The DOM ready check for Internet Explorer
|
686
703
|
function doScrollCheck() {
|
687
704
|
if (handled) return;
|
@@ -701,7 +718,7 @@ var spade ;
|
|
701
718
|
|
702
719
|
// Mozilla, Opera and webkit nightlies currently support this event
|
703
720
|
if (document.addEventListener) {
|
704
|
-
|
721
|
+
|
705
722
|
handler = function() {
|
706
723
|
if (handled) return;
|
707
724
|
handled = true;
|
@@ -709,15 +726,15 @@ var spade ;
|
|
709
726
|
window.removeEventListener('load', handler, false);
|
710
727
|
callback();
|
711
728
|
};
|
712
|
-
|
729
|
+
|
713
730
|
document.addEventListener( "DOMContentLoaded", handler, false);
|
714
|
-
|
731
|
+
|
715
732
|
// A fallback to window.onload, that will always work
|
716
733
|
window.addEventListener( "load", handler, false );
|
717
734
|
|
718
735
|
// If IE event model is used
|
719
736
|
} else if ( document.attachEvent ) {
|
720
|
-
|
737
|
+
|
721
738
|
handler = function() {
|
722
739
|
if (!handled && document.readyState === "complete") {
|
723
740
|
handled = true;
|
@@ -730,7 +747,7 @@ var spade ;
|
|
730
747
|
// ensure firing before onload,
|
731
748
|
// maybe late but safe also for iframes
|
732
749
|
document.attachEvent("onreadystatechange", handler);
|
733
|
-
|
750
|
+
|
734
751
|
// A fallback to window.onload, that will always work
|
735
752
|
window.attachEvent( "onload", handler);
|
736
753
|
|
@@ -744,88 +761,88 @@ var spade ;
|
|
744
761
|
if ( document.documentElement.doScroll && toplevel ) doScrollCheck();
|
745
762
|
}
|
746
763
|
};
|
747
|
-
|
764
|
+
|
748
765
|
// ..........................................................
|
749
766
|
// Compiler Class
|
750
|
-
//
|
751
|
-
|
767
|
+
//
|
768
|
+
|
752
769
|
Compiler = function() {};
|
753
770
|
Cp = Compiler.prototype;
|
754
|
-
|
771
|
+
|
755
772
|
Cp.setup = function(sandbox) {
|
756
773
|
if (sandbox.isIsolated) throw new Error("Isolated Sandbox not supported");
|
757
774
|
};
|
758
|
-
|
775
|
+
|
759
776
|
Cp.compile = function(text, sandbox, filename) {
|
760
777
|
return eval(text);
|
761
778
|
};
|
762
|
-
|
779
|
+
|
763
780
|
Cp.teardown = function(sandbox) {
|
764
781
|
// noop by default
|
765
782
|
};
|
766
|
-
|
783
|
+
|
767
784
|
// ..........................................................
|
768
|
-
// Spade Class - defined so we can recreate
|
769
|
-
//
|
770
|
-
|
785
|
+
// Spade Class - defined so we can recreate
|
786
|
+
//
|
787
|
+
|
771
788
|
Spade = function() {
|
772
789
|
this.loader = new this.Loader(this);
|
773
790
|
this.compiler = new this.Compiler(this);
|
774
791
|
this.defaultSandbox = this.sandbox();
|
775
|
-
this._factories = {};
|
792
|
+
this._factories = {};
|
776
793
|
this._packages = {};
|
777
|
-
|
794
|
+
|
778
795
|
// register this instance as the result of the spade package.
|
779
796
|
var inst = this;
|
780
797
|
this.register('spade', { "name": "spade", "version": this.VERSION });
|
781
798
|
this.register('spade/main', function(r, e, m) { m.exports = inst; });
|
782
799
|
};
|
783
|
-
|
800
|
+
|
784
801
|
Tp = Spade.prototype;
|
785
802
|
|
786
803
|
Tp.VERSION = "0.1.0";
|
787
|
-
|
804
|
+
|
788
805
|
// expose the classes. We do it this way so that you can create a new
|
789
806
|
// Spade instance and treat it like the spade module
|
790
807
|
Tp.Spade = Spade;
|
791
808
|
Tp.Sandbox = Sandbox;
|
792
809
|
Tp.Loader = Loader;
|
793
810
|
Tp.Compiler = Compiler;
|
794
|
-
|
811
|
+
|
795
812
|
Tp.env = function() {
|
796
813
|
if (!this.ENV) this.ENV = 'undefined' !== typeof ENV ? ENV : {};
|
797
814
|
if (!this.ENV.SPADE_PLATFORM) this.ENV.SPADE_PLATFORM = SPADE_PLATFORM;
|
798
815
|
if (!this.ENV.LANG) this.ENV.LANG = LANG;
|
799
816
|
return this.ENV;
|
800
817
|
};
|
801
|
-
|
818
|
+
|
802
819
|
Tp.argv = function() {
|
803
820
|
if (!this.ARGV) this.ARGV = 'undefined' !== typeof ARGV ? ARGV : [];
|
804
821
|
return this.ARGV;
|
805
822
|
};
|
806
|
-
|
823
|
+
|
807
824
|
/**
|
808
825
|
Expose the spade require methods to the global context. This should allow
|
809
|
-
your global code to access spade in the same way that normal modules
|
826
|
+
your global code to access spade in the same way that normal modules
|
810
827
|
would.
|
811
828
|
*/
|
812
829
|
Tp.globalize = function() {
|
813
830
|
var spade = this;
|
814
|
-
|
831
|
+
|
815
832
|
// save old info for conflict...
|
816
833
|
this._conflict = {
|
817
834
|
require: 'undefined' !== typeof require ? require : undefined,
|
818
835
|
ENV: 'undefined' !== typeof ENV ? ENV : undefined,
|
819
836
|
ARGV: 'undefined' !== typeof ARGV ? ARGV : undefined
|
820
837
|
};
|
821
|
-
|
838
|
+
|
822
839
|
require = function() { return spade.require.apply(spade,arguments); };
|
823
840
|
['async', 'sandbox', 'exists', 'url'].forEach(function(key) {
|
824
841
|
require[key] = function() { return spade[key].apply(spade, arguments);};
|
825
842
|
});
|
826
|
-
|
843
|
+
|
827
844
|
ENV = this.env();
|
828
|
-
ARGV = this.argv();
|
845
|
+
ARGV = this.argv();
|
829
846
|
return this;
|
830
847
|
};
|
831
848
|
|
@@ -843,77 +860,89 @@ var spade ;
|
|
843
860
|
}
|
844
861
|
return this;
|
845
862
|
};
|
846
|
-
|
863
|
+
|
847
864
|
/**
|
848
865
|
Returns a new sandbox instance attached to the current spade instance.
|
849
866
|
Can isolate if preferred.
|
850
|
-
|
867
|
+
|
851
868
|
@param {Boolean} isolate
|
852
|
-
true if you want the sandbox to be isolated. Throws exception if
|
869
|
+
true if you want the sandbox to be isolated. Throws exception if
|
853
870
|
platform cannot isolate.
|
854
|
-
|
871
|
+
|
855
872
|
@returns {Sandbox} sandbox instance
|
856
873
|
*/
|
857
874
|
Tp.sandbox = function(name, isolate) {
|
858
875
|
return new this.Sandbox(this, name, isolate);
|
859
876
|
};
|
860
|
-
|
877
|
+
|
861
878
|
/**
|
862
879
|
Register a module or package information. You can pass one of the
|
863
880
|
following:
|
864
|
-
|
881
|
+
|
865
882
|
'module/id', 'module body string'
|
866
883
|
'module/id', function() { module func }
|
867
884
|
'module/id', { exports: 'foo' }
|
868
885
|
'module/id' - just register module id and no body to indicate presence
|
869
|
-
|
870
|
-
Note also that if you pass just a packageId, it will be normalized to
|
886
|
+
|
887
|
+
Note also that if you pass just a packageId, it will be normalized to
|
871
888
|
packageId/~package. This is how you register a package.
|
872
|
-
|
889
|
+
|
873
890
|
@param {String} id
|
874
891
|
The module or package id
|
875
|
-
|
892
|
+
|
876
893
|
@param {String|Function|Hash} data
|
877
894
|
A module function, module body (as string), or hash of exports to use.
|
878
|
-
|
895
|
+
|
879
896
|
@param {String} opts
|
880
|
-
Additional metadata only if you are registering a module factory. Known
|
897
|
+
Additional metadata only if you are registering a module factory. Known
|
881
898
|
keys include 'filename' and 'format' (for compilation of DSLs).
|
882
|
-
|
899
|
+
|
883
900
|
*/
|
884
901
|
Tp.register = function(id, data, opts) {
|
885
|
-
if (!data) data = K ;
|
886
|
-
var t = typeof data, isExtern, factory;
|
902
|
+
if (!data) data = K ;
|
903
|
+
var t = typeof data, isExtern, factory, isPkg;
|
887
904
|
|
888
|
-
// register - note packages can only accept hashes
|
889
905
|
id = normalize(id, null, null, true);
|
890
|
-
|
906
|
+
isPkg = id.slice(-9) === '/~package';
|
907
|
+
|
908
|
+
// register - note packages can only accept hashes
|
909
|
+
if (isPkg && 'object'!==typeof data) {
|
891
910
|
throw new Error('You can only register hashes for packages');
|
892
911
|
}
|
893
|
-
|
894
|
-
|
912
|
+
|
913
|
+
factory = { data: data };
|
895
914
|
factory.filename = opts && opts.filename ? opts.filename : id;
|
896
915
|
factory.format = opts && opts.format ? opts.format : 'js';
|
897
916
|
|
917
|
+
// Store with generic id if none, or if JS
|
918
|
+
if (!this._factories[id] || factory.format === 'js') {
|
919
|
+
this._factories[id] = factory;
|
920
|
+
}
|
921
|
+
|
922
|
+
// Store with format
|
923
|
+
if (!isPkg) {
|
924
|
+
this._factories[id+'.'+factory.format] = factory;
|
925
|
+
}
|
926
|
+
|
898
927
|
return this;
|
899
928
|
};
|
900
929
|
|
901
930
|
/**
|
902
|
-
Efficient way to register external packages. Pass a hash of packageIds
|
931
|
+
Efficient way to register external packages. Pass a hash of packageIds
|
903
932
|
and source URLs. If the package is already registered, the extern will
|
904
933
|
not replace it so this is safe to call multiple times.
|
905
934
|
*/
|
906
935
|
Tp.externs = function(externs, extern) {
|
907
936
|
var tmp, packages = this._packages;
|
908
|
-
|
937
|
+
|
909
938
|
// normalize method call.
|
910
939
|
if ('string' === typeof externs) {
|
911
|
-
tmp = {};
|
912
|
-
tmp[externs] = extern;
|
913
|
-
externs = tmp;
|
940
|
+
tmp = {};
|
941
|
+
tmp[externs] = extern;
|
942
|
+
externs = tmp;
|
914
943
|
extern = null;
|
915
944
|
}
|
916
|
-
|
945
|
+
|
917
946
|
for(var packageId in externs) {
|
918
947
|
if (!externs.hasOwnProperty(packageId)) continue;
|
919
948
|
if (packages[packageId] && !packages[packageId].extern) continue;
|
@@ -924,20 +953,20 @@ var spade ;
|
|
924
953
|
this.register(packageId, extern);
|
925
954
|
}
|
926
955
|
};
|
927
|
-
|
956
|
+
|
928
957
|
/**
|
929
958
|
Require a module from the default sandbox.
|
930
|
-
|
959
|
+
|
931
960
|
@param {String} id
|
932
961
|
The module id.
|
933
|
-
|
934
|
-
@returns {Hash} module exports
|
962
|
+
|
963
|
+
@returns {Hash} module exports
|
935
964
|
*/
|
936
965
|
Tp.require = function(id) {
|
937
966
|
return this.defaultSandbox.require(id, this.defaultSandbox.callerId);
|
938
967
|
};
|
939
968
|
|
940
|
-
|
969
|
+
|
941
970
|
/**
|
942
971
|
Async load a module if it is not already a registered factory. Invoke
|
943
972
|
the passed callback with an optional error object when the module is
|
@@ -946,17 +975,17 @@ var spade ;
|
|
946
975
|
Tp.async = function(id, callback) {
|
947
976
|
return this.defaultSandbox.async(id, callback);
|
948
977
|
};
|
949
|
-
|
978
|
+
|
950
979
|
Tp.exists = function(id) {
|
951
980
|
return this.defaultSandbox.exists(id);
|
952
981
|
};
|
953
|
-
|
982
|
+
|
954
983
|
Tp.url = function(id, ext) {
|
955
984
|
return this.defaultSandbox.url(id, ext);
|
956
985
|
};
|
957
|
-
|
986
|
+
|
958
987
|
function _collectFormats(spade, ret, pkg) {
|
959
|
-
|
988
|
+
|
960
989
|
function extractFormats(formats) {
|
961
990
|
if (formats) {
|
962
991
|
Object.keys(formats).forEach(function(key) {
|
@@ -982,29 +1011,36 @@ var spade ;
|
|
982
1011
|
Called by the sandbox to get a factory object for the named moduleId
|
983
1012
|
*/
|
984
1013
|
Tp.loadFactory = function(id, callback) {
|
985
|
-
var pkg, formats,
|
1014
|
+
var pkg, formats, format, data, ret;
|
986
1015
|
|
987
1016
|
// find any formats the current package might know about. Note that for
|
988
|
-
// lazy-loaders this may not be entirely up to date (since not all pkgs
|
1017
|
+
// lazy-loaders this may not be entirely up to date (since not all pkgs
|
989
1018
|
// are registered right away)
|
990
1019
|
pkg = this.package(id);
|
991
1020
|
formats = pkg ? _collectFormats(this, ['js'], pkg) : ['js'];
|
992
|
-
|
1021
|
+
|
1022
|
+
data = parseIdFormats(id, formats);
|
1023
|
+
id = data.id;
|
1024
|
+
format = data.format;
|
1025
|
+
formats = data.formats;
|
1026
|
+
|
1027
|
+
ret = format ? this._factories[id+'.'+format] : this._factories[id];
|
1028
|
+
|
993
1029
|
if (callback) {
|
994
1030
|
if (!ret) {
|
995
1031
|
if (this.loader && this.loader.loadFactory) {
|
996
1032
|
this.loader.loadFactory(this, id, formats, callback);
|
997
1033
|
} else callback(new Error('Module '+id+' not found'));
|
998
1034
|
} else callback();
|
999
|
-
|
1035
|
+
|
1000
1036
|
} else if (!ret && this.loader && this.loader.loadFactory) {
|
1001
1037
|
this.loader.loadFactory(this, id, formats);
|
1002
|
-
ret = this._factories[id];
|
1038
|
+
ret = format ? this._factories[id+'.'+format] : this._factories[id];
|
1003
1039
|
}
|
1004
1040
|
|
1005
1041
|
return ret ;
|
1006
1042
|
};
|
1007
|
-
|
1043
|
+
|
1008
1044
|
/**
|
1009
1045
|
Called by the sandbox to determine if the named id exists on the system.
|
1010
1046
|
The id should already be normalized. If the id is not yet registered, the
|
@@ -1013,13 +1049,14 @@ var spade ;
|
|
1013
1049
|
Tp.factoryExists = function(id) {
|
1014
1050
|
if (this._factories[id]) return true;
|
1015
1051
|
if (!this.loader || !this.loader.exists) return false;
|
1016
|
-
|
1052
|
+
|
1017
1053
|
var pkg = this.package(id),
|
1018
|
-
formats = pkg ? _collectFormats(this, ['js'], pkg) : ['js']
|
1019
|
-
|
1020
|
-
|
1054
|
+
formats = pkg ? _collectFormats(this, ['js'], pkg) : ['js'],
|
1055
|
+
data = parseIdFormats(id, formats);
|
1056
|
+
|
1057
|
+
return this.loader.exists(this, data.id, data.formats);
|
1021
1058
|
};
|
1022
|
-
|
1059
|
+
|
1023
1060
|
/**
|
1024
1061
|
Returns the package info, if any, for the named module or packageId
|
1025
1062
|
*/
|
@@ -1028,7 +1065,7 @@ var spade ;
|
|
1028
1065
|
var ret = this._factories[id];
|
1029
1066
|
return ret ? ret.data : null;
|
1030
1067
|
};
|
1031
|
-
|
1068
|
+
|
1032
1069
|
/**
|
1033
1070
|
Normalize a moduleId, expanding it if needed.
|
1034
1071
|
*/
|
@@ -1036,7 +1073,7 @@ var spade ;
|
|
1036
1073
|
return normalize(id, contextId);
|
1037
1074
|
};
|
1038
1075
|
|
1039
|
-
// maps the passed ID to a potentially location specific ID. This gives
|
1076
|
+
// maps the passed ID to a potentially location specific ID. This gives
|
1040
1077
|
// the loader a way to vary the factory function returned for a given id
|
1041
1078
|
// per sandbox
|
1042
1079
|
Tp.resolve = function(id, sandbox) {
|
@@ -1044,19 +1081,19 @@ var spade ;
|
|
1044
1081
|
return this.loader.resolve(id, sandbox);
|
1045
1082
|
} else return id;
|
1046
1083
|
};
|
1047
|
-
|
1048
|
-
// uses the loader to invoke when the app is ready. For the browser this
|
1084
|
+
|
1085
|
+
// uses the loader to invoke when the app is ready. For the browser this
|
1049
1086
|
// is on the ready event.
|
1050
1087
|
Tp.ready = function(callback) {
|
1051
1088
|
switch(this.readyState) {
|
1052
1089
|
case 'ready':
|
1053
1090
|
callback();
|
1054
1091
|
break;
|
1055
|
-
|
1092
|
+
|
1056
1093
|
case 'scheduled':
|
1057
1094
|
this._readyQueue.push(callback);
|
1058
1095
|
break;
|
1059
|
-
|
1096
|
+
|
1060
1097
|
default:
|
1061
1098
|
this._readyQueue = [callback];
|
1062
1099
|
this.readyState = 'scheduled';
|
@@ -1068,18 +1105,18 @@ var spade ;
|
|
1068
1105
|
that.readyState = 'ready';
|
1069
1106
|
for(var idx=0;idx<len;idx++) queue[idx]();
|
1070
1107
|
});
|
1071
|
-
|
1108
|
+
|
1072
1109
|
} else {
|
1073
1110
|
throw new Error('Loader does not support activate on ready state');
|
1074
1111
|
}
|
1075
1112
|
}
|
1076
1113
|
};
|
1077
|
-
|
1114
|
+
|
1078
1115
|
// instantiate spade and also attach class for testing
|
1079
1116
|
spade = new Spade();
|
1080
1117
|
|
1081
|
-
// in the browser - if ENV and ARGS are not defined, just create some
|
1082
|
-
// reasonable defaults. We assume that when loading strobe from the CLI
|
1118
|
+
// in the browser - if ENV and ARGS are not defined, just create some
|
1119
|
+
// reasonable defaults. We assume that when loading strobe from the CLI
|
1083
1120
|
// these will already be setup.
|
1084
1121
|
if (SPADE_PLATFORM.engine === 'browser') spade.globalize();
|
1085
1122
|
|