opal 0.6.3 → 0.7.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.spectator +2 -0
- data/.spectator-mspec +3 -0
- data/.travis.yml +8 -11
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTING.md +8 -43
- data/Gemfile +15 -4
- data/Guardfile +77 -0
- data/README.md +15 -9
- data/Rakefile +36 -12
- data/benchmarks/operators.rb +11 -0
- data/bin/opal +10 -13
- data/bin/opal-build +4 -4
- data/bin/opal-mspec +10 -0
- data/bin/opal-repl +4 -3
- data/examples/sinatra/Gemfile +1 -1
- data/examples/sinatra/config.ru +3 -3
- data/lib/mspec/opal/main.rb.erb +2 -2
- data/lib/mspec/opal/rake_task.rb +31 -24
- data/lib/mspec/opal/runner.rb +18 -1
- data/lib/mspec/opal/sprockets.js +17 -0
- data/lib/opal.rb +1 -34
- data/lib/opal/builder.rb +92 -58
- data/lib/opal/builder_processors.rb +165 -0
- data/lib/opal/cli.rb +85 -144
- data/lib/opal/cli_options.rb +136 -90
- data/lib/opal/cli_runners.rb +10 -0
- data/lib/opal/cli_runners/nodejs.rb +56 -0
- data/lib/opal/cli_runners/phantom.js +35 -0
- data/lib/opal/cli_runners/phantomjs.rb +28 -0
- data/lib/opal/cli_runners/server.rb +54 -0
- data/lib/opal/compiler.rb +35 -16
- data/lib/opal/erb.rb +29 -15
- data/lib/opal/hike_path_finder.rb +18 -0
- data/lib/opal/nodes.rb +1 -0
- data/lib/opal/nodes/call.rb +107 -26
- data/lib/opal/nodes/call_special.rb +31 -6
- data/lib/opal/nodes/class.rb +2 -2
- data/lib/opal/nodes/constants.rb +5 -20
- data/lib/opal/nodes/def.rb +4 -4
- data/lib/opal/nodes/defined.rb +3 -3
- data/lib/opal/nodes/definitions.rb +1 -1
- data/lib/opal/nodes/for.rb +35 -0
- data/lib/opal/nodes/helpers.rb +2 -2
- data/lib/opal/nodes/iter.rb +3 -3
- data/lib/opal/nodes/literal.rb +10 -2
- data/lib/opal/nodes/masgn.rb +2 -2
- data/lib/opal/nodes/module.rb +2 -2
- data/lib/opal/nodes/scope.rb +1 -0
- data/lib/opal/nodes/singleton_class.rb +2 -2
- data/lib/opal/nodes/super.rb +2 -2
- data/lib/opal/nodes/top.rb +30 -3
- data/lib/opal/parser.rb +15 -1
- data/lib/opal/parser/grammar.rb +2571 -2452
- data/lib/opal/parser/grammar.y +37 -5
- data/lib/opal/parser/keywords.rb +2 -0
- data/lib/opal/parser/lexer.rb +21 -11
- data/lib/opal/path_reader.rb +28 -0
- data/lib/opal/paths.rb +38 -0
- data/lib/opal/source_map.rb +32 -15
- data/lib/opal/sprockets/environment.rb +9 -2
- data/lib/opal/sprockets/erb.rb +1 -2
- data/lib/opal/sprockets/path_reader.rb +34 -0
- data/lib/opal/sprockets/processor.rb +40 -39
- data/lib/opal/sprockets/server.rb +47 -33
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +10 -5
- data/opal/README.md +6 -0
- data/opal/corelib/array.rb +36 -4
- data/opal/corelib/array/inheritance.rb +6 -6
- data/opal/corelib/basic_object.rb +9 -9
- data/opal/corelib/boolean.rb +1 -1
- data/opal/corelib/class.rb +12 -12
- data/opal/corelib/dir.rb +20 -0
- data/opal/corelib/enumerable.rb +42 -42
- data/opal/corelib/enumerator.rb +1 -1
- data/opal/corelib/error.rb +2 -2
- data/opal/corelib/file.rb +56 -0
- data/opal/corelib/hash.rb +5 -5
- data/opal/corelib/helpers.rb +3 -3
- data/opal/corelib/io.rb +13 -10
- data/opal/corelib/kernel.rb +44 -68
- data/opal/corelib/method.rb +1 -1
- data/opal/corelib/module.rb +89 -114
- data/opal/corelib/nil_class.rb +1 -1
- data/opal/corelib/numeric.rb +27 -23
- data/opal/corelib/proc.rb +5 -5
- data/opal/corelib/range.rb +8 -4
- data/opal/corelib/regexp.rb +5 -5
- data/opal/corelib/runtime.js +589 -272
- data/opal/corelib/string.rb +52 -37
- data/opal/corelib/string/inheritance.rb +5 -5
- data/opal/corelib/time.rb +102 -52
- data/opal/corelib/variables.rb +3 -3
- data/opal/opal.rb +2 -0
- data/package.json +9 -0
- data/spec/filters/bugs/array.rb +0 -6
- data/spec/filters/bugs/language.rb +4 -0
- data/spec/filters/bugs/numeric.rb +7 -6
- data/spec/filters/bugs/opal.rb +2 -0
- data/spec/filters/bugs/regexp.rb +4 -0
- data/spec/filters/bugs/string.rb +0 -7
- data/spec/filters/bugs/stringscanner.rb +4 -1
- data/spec/filters/unsupported/private_methods.rb +2 -0
- data/spec/lib/builder_processors_spec.rb +27 -0
- data/spec/lib/builder_spec.rb +66 -0
- data/spec/{cli → lib}/cli_spec.rb +60 -5
- data/spec/{cli → lib}/compiler_spec.rb +66 -5
- data/spec/{cli → lib}/dependency_resolver_spec.rb +1 -1
- data/spec/lib/fixtures/no_requires.rb +1 -0
- data/spec/{cli → lib}/fixtures/opal_file.rb +0 -0
- data/spec/lib/fixtures/require_tree_test.rb +3 -0
- data/spec/lib/fixtures/required_tree_test/required_file1.rb +1 -0
- data/spec/lib/fixtures/required_tree_test/required_file2.rb +1 -0
- data/spec/lib/fixtures/requires.rb +7 -0
- data/spec/{cli → lib}/fixtures/sprockets_file.js.rb +0 -0
- data/spec/lib/fixtures/sprockets_require_tree_test.rb +3 -0
- data/spec/lib/hike_path_finder_spec.rb +23 -0
- data/spec/{cli → lib}/lexer_spec.rb +1 -1
- data/spec/{cli → lib}/parser/alias_spec.rb +1 -1
- data/spec/{cli → lib}/parser/and_spec.rb +1 -1
- data/spec/{cli → lib}/parser/attrasgn_spec.rb +1 -1
- data/spec/{cli → lib}/parser/begin_spec.rb +1 -1
- data/spec/{cli → lib}/parser/block_spec.rb +1 -1
- data/spec/{cli → lib}/parser/break_spec.rb +1 -1
- data/spec/{cli → lib}/parser/call_spec.rb +1 -1
- data/spec/{cli → lib}/parser/class_spec.rb +1 -1
- data/spec/{cli → lib}/parser/comments_spec.rb +1 -1
- data/spec/{cli → lib}/parser/def_spec.rb +1 -1
- data/spec/{cli → lib}/parser/if_spec.rb +1 -1
- data/spec/{cli → lib}/parser/iter_spec.rb +1 -1
- data/spec/{cli → lib}/parser/lambda_spec.rb +1 -1
- data/spec/{cli → lib}/parser/literal_spec.rb +1 -1
- data/spec/{cli → lib}/parser/masgn_spec.rb +1 -1
- data/spec/{cli → lib}/parser/module_spec.rb +1 -1
- data/spec/{cli → lib}/parser/not_spec.rb +1 -1
- data/spec/{cli → lib}/parser/op_asgn1_spec.rb +1 -1
- data/spec/{cli → lib}/parser/op_asgn2_spec.rb +1 -1
- data/spec/{cli → lib}/parser/or_spec.rb +1 -1
- data/spec/{cli → lib}/parser/return_spec.rb +1 -1
- data/spec/{cli → lib}/parser/sclass_spec.rb +1 -1
- data/spec/{cli → lib}/parser/string_spec.rb +8 -1
- data/spec/{cli → lib}/parser/super_spec.rb +1 -1
- data/spec/lib/parser/unary_spec.rb +48 -0
- data/spec/{cli → lib}/parser/undef_spec.rb +1 -1
- data/spec/{cli → lib}/parser/unless_spec.rb +1 -1
- data/spec/{cli → lib}/parser/variables_spec.rb +1 -1
- data/spec/{cli → lib}/parser/while_spec.rb +1 -1
- data/spec/{cli → lib}/parser/yield_spec.rb +1 -1
- data/spec/lib/path_reader_spec.rb +24 -0
- data/spec/lib/shared/path_finder_shared.rb +19 -0
- data/spec/lib/shared/path_reader_shared.rb +31 -0
- data/spec/lib/spec_helper.rb +9 -0
- data/spec/lib/sprockets/environment_spec.rb +30 -0
- data/spec/{cli → lib}/sprockets/erb_spec.rb +1 -1
- data/spec/lib/sprockets/path_reader_spec.rb +25 -0
- data/spec/{cli → lib}/sprockets/processor_spec.rb +9 -2
- data/spec/lib/sprockets/server_spec.rb +20 -0
- data/spec/opal/compiler/irb_spec.rb +11 -11
- data/spec/opal/core/fixtures/require_tree_files/file 1.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_files/file 2.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_files/file 3.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_files/file 4.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_files/file 5.rb +1 -0
- data/spec/opal/core/kernel/require_tree_spec.rb +7 -0
- data/spec/opal/core/kernel/respond_to_spec.rb +2 -2
- data/spec/opal/core/runtime/method_missing_spec.rb +19 -0
- data/spec/opal/core/source_map_spec.rb +2 -2
- data/spec/opal/core/string_spec.rb +11 -0
- data/spec/opal/stdlib/erb/erb_spec.rb +0 -1
- data/spec/opal/stdlib/thread/mutex_spec.rb +40 -0
- data/spec/opal/stdlib/thread/thread_queue_spec.rb +32 -0
- data/spec/opal/stdlib/thread/thread_spec.rb +60 -0
- data/spec/rubyspecs +54 -11
- data/spec/spec_helper.rb +18 -3
- data/spec/support/mspec_rspec_adapter.rb +33 -0
- data/spec/{cli/spec_helper.rb → support/parser_helpers.rb} +10 -10
- data/stdlib/README.md +3 -0
- data/stdlib/benchmark.rb +10 -0
- data/stdlib/date.rb +2 -2
- data/stdlib/dir.rb +1 -5
- data/stdlib/file.rb +1 -7
- data/stdlib/json.rb +10 -1
- data/stdlib/native.rb +5 -5
- data/stdlib/nodejs.rb +5 -0
- data/stdlib/nodejs/dir.rb +13 -0
- data/stdlib/nodejs/file.rb +98 -0
- data/stdlib/nodejs/fileutils.rb +26 -0
- data/stdlib/nodejs/io.rb +2 -0
- data/stdlib/nodejs/irb.rb +45 -0
- data/stdlib/nodejs/process.rb +16 -0
- data/stdlib/nodejs/require.rb +32 -0
- data/stdlib/nodejs/rubygems.rb +68 -0
- data/stdlib/nodejs/runtime.rb +25 -0
- data/stdlib/nodejs/yaml.rb +11 -0
- data/stdlib/opal-parser.rb +1 -2
- data/stdlib/opal-source-maps.rb +2 -0
- data/stdlib/phantomjs.rb +8 -0
- data/stdlib/process.rb +10 -0
- data/stdlib/promise.rb +12 -4
- data/stdlib/set.rb +27 -0
- data/stdlib/source_map.rb +5 -63
- data/stdlib/source_map/map.rb +220 -0
- data/stdlib/source_map/mapping.rb +26 -0
- data/stdlib/source_map/offset.rb +88 -0
- data/stdlib/source_map/version.rb +3 -0
- data/stdlib/source_map/vlq.rb +77 -101
- data/stdlib/sourcemap.rb +1 -0
- data/stdlib/strscan.rb +7 -1
- data/stdlib/template.rb +1 -1
- data/stdlib/thread.rb +147 -7
- metadata +238 -104
- data/lib/mspec/opal/mspec_fixes.rb +0 -87
- data/spec/cli/sprockets/environment_spec.rb +0 -14
- data/spec/filters/bugs/symbol.rb +0 -5
- data/spec/opal/core/kernel/warn_spec.rb +0 -83
- data/spec/opal/core/language/numbers_spec.rb +0 -60
- data/stdlib/opal-source-maps.js.erb +0 -2
- data/stdlib/source_map/generator.rb +0 -251
- data/stdlib/source_map/parser.rb +0 -102
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'mspec/mocks/mock'
|
2
|
-
require 'mspec/guards/guard'
|
3
|
-
|
4
|
-
# 1. Opal does not support mutable strings
|
5
|
-
class ExceptionState
|
6
|
-
def initialize(state, location, exception)
|
7
|
-
@exception = exception
|
8
|
-
|
9
|
-
@description = location ? ["An exception occurred during: #{location}"] : []
|
10
|
-
if state
|
11
|
-
@description << "\n" unless @description.empty?
|
12
|
-
@description << state.description
|
13
|
-
@describe = state.describe
|
14
|
-
@it = state.it
|
15
|
-
@description = @description.join ""
|
16
|
-
else
|
17
|
-
@describe = @it = ""
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# 2. class_eval() doesnt except string parameter
|
23
|
-
def Mock.install_method(obj, sym, type=nil)
|
24
|
-
meta = obj.singleton_class
|
25
|
-
|
26
|
-
key = replaced_key obj, sym
|
27
|
-
sym = sym.to_sym
|
28
|
-
|
29
|
-
if (sym == :respond_to? or mock_respond_to?(obj, sym, true)) and !replaced?(key.first)
|
30
|
-
meta.__send__ :alias_method, key.first, sym
|
31
|
-
end
|
32
|
-
|
33
|
-
# meta.class_eval <<-END
|
34
|
-
# def #{sym}(*args, &block)
|
35
|
-
# Mock.verify_call self, :#{sym}, *args, &block
|
36
|
-
# end
|
37
|
-
# END
|
38
|
-
meta.class_eval {
|
39
|
-
define_method(sym) do |*args, &block|
|
40
|
-
Mock.verify_call self, sym, *args, &block
|
41
|
-
end
|
42
|
-
}
|
43
|
-
|
44
|
-
proxy = MockProxy.new type
|
45
|
-
|
46
|
-
if proxy.mock?
|
47
|
-
MSpec.expectation
|
48
|
-
MSpec.actions :expectation, MSpec.current.state
|
49
|
-
end
|
50
|
-
|
51
|
-
if proxy.stub?
|
52
|
-
stubs[key].unshift proxy
|
53
|
-
else
|
54
|
-
mocks[key] << proxy
|
55
|
-
end
|
56
|
-
objects[key] = obj
|
57
|
-
|
58
|
-
proxy
|
59
|
-
end
|
60
|
-
|
61
|
-
# 3. Waiting for: https://github.com/rubyspec/mspec/pull/40
|
62
|
-
class SpecGuard
|
63
|
-
def implementation?(*args)
|
64
|
-
args.any? do |name|
|
65
|
-
!!case name
|
66
|
-
when :rubinius
|
67
|
-
RUBY_NAME =~ /^rbx/
|
68
|
-
when :ruby
|
69
|
-
RUBY_NAME =~ /^ruby/
|
70
|
-
when :jruby
|
71
|
-
RUBY_NAME =~ /^jruby/
|
72
|
-
when :ironruby
|
73
|
-
RUBY_NAME =~ /^ironruby/
|
74
|
-
when :macruby
|
75
|
-
RUBY_NAME =~ /^macruby/
|
76
|
-
when :maglev
|
77
|
-
RUBY_NAME =~ /^maglev/
|
78
|
-
when :topaz
|
79
|
-
RUBY_NAME =~ /^topaz/
|
80
|
-
when :opal
|
81
|
-
RUBY_NAME =~ /^opal/
|
82
|
-
else
|
83
|
-
false
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'cli/spec_helper'
|
2
|
-
require 'opal/sprockets/environment'
|
3
|
-
|
4
|
-
describe Opal::Environment do
|
5
|
-
let(:env) { described_class.new }
|
6
|
-
let(:logical_path) { 'sprockets_file' }
|
7
|
-
|
8
|
-
before { env.append_path File.expand_path('../../fixtures/', __FILE__) }
|
9
|
-
|
10
|
-
it 'compiles Ruby to JS' do
|
11
|
-
expect(env[logical_path].source).to include('$puts(')
|
12
|
-
expect(env[logical_path+'.js'].source).to include('$puts(')
|
13
|
-
end
|
14
|
-
end
|
data/spec/filters/bugs/symbol.rb
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
opal_filter "Symbol" do
|
2
|
-
fails "Symbol#to_proc sends self to arguments passed when calling #call on the Proc"
|
3
|
-
fails "Symbol#to_proc raises an ArgumentError when calling #call on the Proc without receiver"
|
4
|
-
fails "Symbol#to_proc passes along the block passed to Proc#call"
|
5
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
describe 'Kernel#warn' do
|
5
|
-
before do
|
6
|
-
@fake_stderr = StringIO.new
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'writes single message to $stderr if $VERBOSE is true' do
|
10
|
-
old_verbose = $VERBOSE
|
11
|
-
$VERBOSE = true
|
12
|
-
|
13
|
-
captured_stderr {
|
14
|
-
warn 'this is a warning message'
|
15
|
-
}.should == 'this is a warning message'
|
16
|
-
|
17
|
-
$VERBOSE = old_verbose
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'writes multiple messages to $stderr if $VERBOSE is true' do
|
21
|
-
old_verbose = $VERBOSE
|
22
|
-
$VERBOSE = true
|
23
|
-
|
24
|
-
captured_stderr {
|
25
|
-
warn 'this is a warning message', 'this is another'
|
26
|
-
}.should == "this is a warning message\nthis is another"
|
27
|
-
|
28
|
-
$VERBOSE = old_verbose
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'does not write empty message to $stderr if $VERBOSE is true' do
|
32
|
-
old_verbose = $VERBOSE
|
33
|
-
$VERBOSE = true
|
34
|
-
|
35
|
-
captured_stderr {
|
36
|
-
warn
|
37
|
-
}.should be_nil
|
38
|
-
|
39
|
-
$VERBOSE = old_verbose
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'does write message to $stderr if $VERBOSE is false' do
|
43
|
-
old_verbose = $VERBOSE
|
44
|
-
$VERBOSE = false
|
45
|
-
|
46
|
-
captured_stderr {
|
47
|
-
warn 'this is a warning message'
|
48
|
-
}.should == 'this is a warning message'
|
49
|
-
|
50
|
-
$VERBOSE = old_verbose
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'does not write message to $stderr if $VERBOSE is nil' do
|
54
|
-
old_verbose = $VERBOSE
|
55
|
-
$VERBOSE = nil
|
56
|
-
|
57
|
-
captured_stderr {
|
58
|
-
warn 'this is a warning message'
|
59
|
-
}.should be_nil
|
60
|
-
|
61
|
-
$VERBOSE = old_verbose
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'returns a nil value' do
|
65
|
-
old_verbose = $VERBOSE
|
66
|
-
$VERBOSE = true
|
67
|
-
|
68
|
-
captured_stderr {
|
69
|
-
(warn 'this is a warning message').should be_nil
|
70
|
-
}
|
71
|
-
|
72
|
-
$VERBOSE = old_verbose
|
73
|
-
end
|
74
|
-
|
75
|
-
def captured_stderr
|
76
|
-
original_stderr = $stderr
|
77
|
-
$stderr = @fake_stderr
|
78
|
-
yield
|
79
|
-
@fake_stderr.tap(&:rewind).read
|
80
|
-
ensure
|
81
|
-
$stderr = original_stderr
|
82
|
-
end
|
83
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
describe "Ruby numbers in various ways" do
|
2
|
-
|
3
|
-
it "the standard way" do
|
4
|
-
435.should == 435
|
5
|
-
end
|
6
|
-
|
7
|
-
it "with underscore separations" do
|
8
|
-
4_35.should == 435
|
9
|
-
end
|
10
|
-
|
11
|
-
it "with some decimals" do
|
12
|
-
4.35.should == 4.35
|
13
|
-
end
|
14
|
-
|
15
|
-
it "with decimals but no integer part should be a SyntaxError" do
|
16
|
-
lambda { eval(".75") }.should raise_error(SyntaxError)
|
17
|
-
lambda { eval("-.75") }.should raise_error(SyntaxError)
|
18
|
-
end
|
19
|
-
|
20
|
-
# TODO : find a better description
|
21
|
-
it "using the e expression" do
|
22
|
-
1.2e-3.should == 0.0012
|
23
|
-
end
|
24
|
-
|
25
|
-
it "the hexdecimal notation" do
|
26
|
-
0xffff.should == 65535
|
27
|
-
end
|
28
|
-
|
29
|
-
it "the binary notation" do
|
30
|
-
0b01011.should == 11
|
31
|
-
0101.should == 5
|
32
|
-
001010.should == 10
|
33
|
-
0b1010.should == 10
|
34
|
-
0b10_10.should == 10
|
35
|
-
end
|
36
|
-
|
37
|
-
it "octal representation" do
|
38
|
-
0377.should == 255
|
39
|
-
0o377.should == 255
|
40
|
-
0o3_77.should == 255
|
41
|
-
end
|
42
|
-
|
43
|
-
ruby_version_is '' ... '1.9' do
|
44
|
-
it "character to numeric shortcut" do
|
45
|
-
?z.should == 122
|
46
|
-
end
|
47
|
-
|
48
|
-
it "character with control character to numeric shortcut" do
|
49
|
-
# Control-Z
|
50
|
-
#?\C-z.should == 26
|
51
|
-
|
52
|
-
# Meta-Z
|
53
|
-
#?\M-z.should == 250
|
54
|
-
|
55
|
-
# Meta-Control-Z
|
56
|
-
#?\M-\C-z.should == 154
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
@@ -1,251 +0,0 @@
|
|
1
|
-
class SourceMap
|
2
|
-
module Generator
|
3
|
-
|
4
|
-
# An object (responding to <<) that will be written to whenever
|
5
|
-
# {add_generated} is called.
|
6
|
-
#
|
7
|
-
# @example
|
8
|
-
#
|
9
|
-
# File.open("/var/www/a.js.min"){ |f|
|
10
|
-
# map = SourceMap.new(:generated_output => f)
|
11
|
-
# map.add_generated('function(a,b,c){minified=1}\n', :source => 'a.js')
|
12
|
-
# map.save('/var/www/a.js.map')
|
13
|
-
# }
|
14
|
-
# File.read('/var/www/a.js.min') == 'function(a,b,c){minified=1}\n'
|
15
|
-
#
|
16
|
-
attr_accessor :generated_output
|
17
|
-
|
18
|
-
# Add the mapping for generated code to this source map.
|
19
|
-
#
|
20
|
-
# The first parameter is the generated text that you're going to add to the output, if
|
21
|
-
# it contains multiple lines of code then it will be added to the source map as
|
22
|
-
# several mappings.
|
23
|
-
#
|
24
|
-
# If present, the second parameter represents the original source of the generated
|
25
|
-
# fragment, and may contain:
|
26
|
-
#
|
27
|
-
# :source => String, # The filename of the source fille that contains this fragment.
|
28
|
-
# :source_line => Integer, # The line in that file that contains this fragment
|
29
|
-
# :source_col => Integer, # The column in that line at which this fragment starts
|
30
|
-
# :name => String # The original name for this variable.
|
31
|
-
# :exact_position => Bool # Whether all lines in the generated fragment came from
|
32
|
-
# the same position in the source.
|
33
|
-
#
|
34
|
-
# The :source key is required to set :source_line, :source_col or :name.
|
35
|
-
#
|
36
|
-
# If unset :source_line and :source_col default to 1,0 for the first line of the
|
37
|
-
# generated fragment.
|
38
|
-
#
|
39
|
-
# Normally :source_line is incremented and :source_col reset at every line break in
|
40
|
-
# the generated code (because we assume that you're copying a verbatim fragment from
|
41
|
-
# the source into the generated code). If that is not the case, you can set
|
42
|
-
# :exact_position => true, and then all lines in the generated output will be given
|
43
|
-
# the same :source_line and :source_col.
|
44
|
-
#
|
45
|
-
# The :name property is used if the fragment you are adding contains only a name that
|
46
|
-
# you have renamed in the source transformation.
|
47
|
-
#
|
48
|
-
# If you'd like to ensure that the source map stays in sync with the generated
|
49
|
-
# source, consider calling {source_map.generated_output = StringIO.new} and then
|
50
|
-
# accessing your generated javascript with {source_map.generated_output.string},
|
51
|
-
# otherwise be careful to always write to both.
|
52
|
-
#
|
53
|
-
# NOTE: By long-standing convention, the first line of a file is numbered 1, not 0.
|
54
|
-
#
|
55
|
-
# NOTE: when generating a source map, you should either use this method always, or use
|
56
|
-
# the {#add_mapping} method always.
|
57
|
-
#
|
58
|
-
def add_generated(text, opts={})
|
59
|
-
if !opts[:source] && (opts[:name] || opts[:source_line] || opts[:source_col])
|
60
|
-
raise "mapping must have :source to have :source_line, :source_col or :name"
|
61
|
-
elsif opts[:source_line] && opts[:source_line] < 1
|
62
|
-
raise "files start on line 1 (got :source_line => #{opts[:source_line]})"
|
63
|
-
elsif !(remain = opts.keys - [:source, :source_line, :source_col, :name, :exact_position]).empty?
|
64
|
-
raise "mapping had unexpected keys: #{remain.inspect}"
|
65
|
-
end
|
66
|
-
|
67
|
-
source_line = opts[:source_line] || 1
|
68
|
-
source_col = opts[:source_col] || 0
|
69
|
-
self.generated_line ||= 1
|
70
|
-
self.generated_col ||= 0
|
71
|
-
|
72
|
-
text.split(/(\n)/).each do |line|
|
73
|
-
if line == "\n"
|
74
|
-
self.generated_line += 1
|
75
|
-
self.generated_col = 0
|
76
|
-
unless opts[:exact_position]
|
77
|
-
source_line += 1
|
78
|
-
source_col = 0
|
79
|
-
end
|
80
|
-
elsif line != ""
|
81
|
-
mapping = {
|
82
|
-
:generated_line => generated_line,
|
83
|
-
:generated_col => generated_col,
|
84
|
-
}
|
85
|
-
if opts[:source]
|
86
|
-
mapping[:source] = opts[:source]
|
87
|
-
mapping[:source_line] = source_line
|
88
|
-
mapping[:source_col] = source_col
|
89
|
-
mapping[:name] = opts[:name] if opts[:name]
|
90
|
-
end
|
91
|
-
|
92
|
-
mappings << mapping
|
93
|
-
|
94
|
-
self.generated_col += line.size
|
95
|
-
source_col += line.size unless opts[:exact_position]
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
generated_output += text if generated_output
|
100
|
-
end
|
101
|
-
|
102
|
-
# Add a mapping to the list for this object.
|
103
|
-
#
|
104
|
-
# A mapping identifies a fragment of code that has been moved around during
|
105
|
-
# transformation from the source file to the generated file. The fragment should
|
106
|
-
# be contiguous and not contain any line breaks.
|
107
|
-
#
|
108
|
-
# Mappings are Hashes with a valid subset of the following 6 keys:
|
109
|
-
#
|
110
|
-
# :generated_line => Integer, # The line in the generated file that contains this fragment.
|
111
|
-
# :generated_col => Integer, # The column in the generated_line that this mapping starts on
|
112
|
-
# :source => String, # The filename of the source fille that contains this fragment.
|
113
|
-
# :source_line => Integer, # The line in that file that contains this fragment.
|
114
|
-
# :source_col => Integer, # The column in that line at which this fragment starts.
|
115
|
-
# :name => String # The original name for this variable (if applicable).
|
116
|
-
#
|
117
|
-
#
|
118
|
-
# The only 3 valid subsets of keys are:
|
119
|
-
# [:generated_line, :generated_col] To indicate that this is a fragment in the
|
120
|
-
# output file that you don't have the source for.
|
121
|
-
#
|
122
|
-
# [:generated_line, :generated_col, :source, :source_line, :source_col] To indicate
|
123
|
-
# that this is a fragment in the output file that you do have the source for.
|
124
|
-
#
|
125
|
-
# [:generated_line, :generated_col, :source, :source_line, :source_col, :name] To
|
126
|
-
# indicate that this is a particular identifier at a particular location in the original.
|
127
|
-
#
|
128
|
-
# Any other combination of keys would produce an invalid source map.
|
129
|
-
#
|
130
|
-
# NOTE: By long-standing convention, the first line of a file is numbered 1, not 0.
|
131
|
-
#
|
132
|
-
# NOTE: when generating a source map, you should either use this method always,
|
133
|
-
# or use the {#add_generated} method always.
|
134
|
-
#
|
135
|
-
def add_mapping(map)
|
136
|
-
if !map[:generated_line] || !map[:generated_col]
|
137
|
-
raise "mapping must have :generated_line and :generated_col"
|
138
|
-
elsif map[:source] && !(map[:source_line] && map[:source_col])
|
139
|
-
raise "mapping must have :source_line and :source_col if it has :source"
|
140
|
-
elsif !map[:source] && (map[:source_line] || map[:source_col])
|
141
|
-
raise "mapping may not have a :source_line or :source_col without a :source"
|
142
|
-
elsif map[:name] && !map[:source]
|
143
|
-
raise "mapping may not have a :name without a :source"
|
144
|
-
elsif map[:source_line] && map[:source_line] < 1
|
145
|
-
raise "files start on line 1 (got :source_line => #{map[:source_line]})"
|
146
|
-
elsif map[:generated_line] < 1
|
147
|
-
raise "files start on line 1 (got :generated_line => #{map[:generated_line]})"
|
148
|
-
elsif !(remain = map.keys - [:generated_line, :generated_col, :source, :source_line, :source_col, :name]).empty?
|
149
|
-
raise "mapping had unexpected keys: #{remain.inspect}"
|
150
|
-
end
|
151
|
-
|
152
|
-
mappings << map
|
153
|
-
end
|
154
|
-
|
155
|
-
# Convert the map into an object suitable for direct serialisation.
|
156
|
-
def as_json
|
157
|
-
serialized_mappings = serialize_mappings!
|
158
|
-
|
159
|
-
{
|
160
|
-
'version' => version,
|
161
|
-
'file' => file,
|
162
|
-
'sourceRoot' => source_root,
|
163
|
-
'sources' => sources,
|
164
|
-
'names' => names,
|
165
|
-
'mappings' => serialized_mappings
|
166
|
-
}
|
167
|
-
end
|
168
|
-
|
169
|
-
# Convert the map to a string.
|
170
|
-
def to_s
|
171
|
-
as_json.to_json
|
172
|
-
end
|
173
|
-
|
174
|
-
# Write this map to a file.
|
175
|
-
def save(file)
|
176
|
-
File.open(file, "w"){ |f| f << to_s }
|
177
|
-
end
|
178
|
-
|
179
|
-
protected
|
180
|
-
|
181
|
-
attr_reader :source_ids, :name_ids
|
182
|
-
attr_accessor :generated_line, :generated_col
|
183
|
-
|
184
|
-
# Get the id for the given file. If we've not
|
185
|
-
# seen this file before, add it to the list.
|
186
|
-
def source_id(file)
|
187
|
-
if (cached = source_ids[file])
|
188
|
-
cached
|
189
|
-
else
|
190
|
-
sources << file
|
191
|
-
source_ids[file] = sources.size - 1
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Get the id for the given name. If we've not
|
196
|
-
# seen this name before, add it to the list.
|
197
|
-
def name_id(name)
|
198
|
-
if (cached = name_ids[file])
|
199
|
-
cached
|
200
|
-
else
|
201
|
-
names << name
|
202
|
-
name_ids[file] = names.size - 1
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# Encode a vlq. As each field in the output should be relative to the
|
207
|
-
# previous occurance of that field, we keep track of each one.
|
208
|
-
def vlq(num, type)
|
209
|
-
ret = num - @previous_vlq[type]
|
210
|
-
@previous_vlq[type] = num
|
211
|
-
VLQ.encode(ret)
|
212
|
-
end
|
213
|
-
|
214
|
-
# Serialize the list of mappings into the string of base64 variable length
|
215
|
-
# quanities. As a side-effect, regenerate the sources and names arrays.
|
216
|
-
def serialize_mappings!
|
217
|
-
# clear all internals as we're about to re-generate them.
|
218
|
-
@sources = []
|
219
|
-
@source_ids = {}
|
220
|
-
@names = []
|
221
|
-
@name_ids = {}
|
222
|
-
@previous_vlq = Hash.new{ 0 }
|
223
|
-
|
224
|
-
return "" if mappings.empty?
|
225
|
-
|
226
|
-
by_lines = mappings.group_by{ |x| x[:generated_line] }
|
227
|
-
|
228
|
-
(1..by_lines.keys.max).map do |line|
|
229
|
-
# reset the generated_col on each line as indicated by the VLQ spec.
|
230
|
-
# (the other values continue to be relative)
|
231
|
-
@previous_vlq[:generated_col] = 0
|
232
|
-
|
233
|
-
fragments = (by_lines[line] || []).sort_by{ |x| x[:generated_col] }
|
234
|
-
fragments.map do |map|
|
235
|
-
serialize_mapping(map)
|
236
|
-
end.join(",")
|
237
|
-
end.join(";")
|
238
|
-
end
|
239
|
-
|
240
|
-
def serialize_mapping(map)
|
241
|
-
item = vlq(map[:generated_col], :generated_col)
|
242
|
-
if map[:source]
|
243
|
-
item += vlq(source_id(map[:source]), :source)
|
244
|
-
item += vlq(map[:source_line] - 1, :source_line)
|
245
|
-
item += vlq(map[:source_col], :source_col)
|
246
|
-
item += vlq(name_id(map[:name]), :name) if map[:name]
|
247
|
-
end
|
248
|
-
item
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|