spade 0.0.6 → 0.0.7
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.
- 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
|
|