jasmine-headless-webkit-firstbanco 0.9.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +89 -0
  5. data/Gemfile +30 -0
  6. data/Guardfile +41 -0
  7. data/README.md +44 -0
  8. data/Rakefile +65 -0
  9. data/bin/jasmine-headless-webkit +11 -0
  10. data/config/cucumber.yml +2 -0
  11. data/ext/jasmine-webkit-specrunner/Info.plist +22 -0
  12. data/ext/jasmine-webkit-specrunner/Makefile.dummy +5 -0
  13. data/ext/jasmine-webkit-specrunner/Page.cpp +15 -0
  14. data/ext/jasmine-webkit-specrunner/Page.h +20 -0
  15. data/ext/jasmine-webkit-specrunner/Runner.cpp +208 -0
  16. data/ext/jasmine-webkit-specrunner/Runner.h +73 -0
  17. data/ext/jasmine-webkit-specrunner/common.pri +8 -0
  18. data/ext/jasmine-webkit-specrunner/extconf.rb +10 -0
  19. data/ext/jasmine-webkit-specrunner/specrunner.cpp +79 -0
  20. data/ext/jasmine-webkit-specrunner/specrunner.pro +5 -0
  21. data/features/bin/failure.feature +7 -0
  22. data/features/bin/files.feature +7 -0
  23. data/features/bin/filtered_run/both_runs.feature +18 -0
  24. data/features/bin/filtered_run/no_full_run.feature +14 -0
  25. data/features/bin/help.feature +7 -0
  26. data/features/bin/quiet_messages.feature +8 -0
  27. data/features/bin/runner_out.feature +8 -0
  28. data/features/bin/spec_files_with_same_basename.feature +7 -0
  29. data/features/bin/success.feature +20 -0
  30. data/features/bin/success_with_js_error.feature +5 -0
  31. data/features/bin/tries_to_leave_page.feature +7 -0
  32. data/features/bin/try_to_click_a_button.feature +7 -0
  33. data/features/bin/two_files_from_src_files.feature +11 -0
  34. data/features/bin/with_coffeescript_error.feature +7 -0
  35. data/features/bin/with_console_log.feature +7 -0
  36. data/features/bin/with_server.feature +7 -0
  37. data/features/bin/with_window_prompt.feature +7 -0
  38. data/features/reporters.feature +24 -0
  39. data/features/runner.feature +34 -0
  40. data/features/steps/given/i_have_test_suite.rb +2 -0
  41. data/features/steps/given/no_existing_file.rb +4 -0
  42. data/features/steps/given/options/i_have_defaults.rb +4 -0
  43. data/features/steps/given/options/i_have_reporters.rb +10 -0
  44. data/features/steps/given/options/i_have_runner_options.rb +3 -0
  45. data/features/steps/then/bin/exit_status_should_be.rb +3 -0
  46. data/features/steps/then/bin/file_should_contain_runner.rb +4 -0
  47. data/features/steps/then/bin/following_files_loaded_in_order.rb +10 -0
  48. data/features/steps/then/bin/i_should_get_help_output.rb +4 -0
  49. data/features/steps/then/bin/output_should_include.rb +3 -0
  50. data/features/steps/then/bin/output_should_not_include.rb +4 -0
  51. data/features/steps/then/reporting/report_does_not_exist.rb +4 -0
  52. data/features/steps/then/reporting/report_should_exist.rb +3 -0
  53. data/features/steps/then/reporting/report_should_have.rb +7 -0
  54. data/features/steps/then/reporting/report_should_have_seed.rb +4 -0
  55. data/features/steps/then/runner/it_should_have_exit_status.rb +3 -0
  56. data/features/steps/then/runner/it_should_include_report_file.rb +4 -0
  57. data/features/steps/then/runner/it_should_not_include_report_file.rb +3 -0
  58. data/features/steps/then/templates/it_should_use_reporter.rb +6 -0
  59. data/features/steps/when/i_delete_file.rb +3 -0
  60. data/features/steps/when/i_get_runner.rb +4 -0
  61. data/features/steps/when/i_get_template_writer.rb +4 -0
  62. data/features/steps/when/i_run_executable.rb +4 -0
  63. data/features/steps/when/i_run_runner.rb +4 -0
  64. data/features/support/env.rb +7 -0
  65. data/jasmine-headless-webkit-firstbanco.gemspec +30 -0
  66. data/lib/autotest/discover.rb +1 -0
  67. data/lib/autotest/jasmine.rb +7 -0
  68. data/lib/autotest/jasmine_mixin.rb +111 -0
  69. data/lib/autotest/jasmine_rspec2.rb +7 -0
  70. data/lib/jasmine-headless-webkit.rb +3 -0
  71. data/lib/jasmine/headless.rb +61 -0
  72. data/lib/jasmine/headless/cacheable_action.rb +85 -0
  73. data/lib/jasmine/headless/coffee_script_cache.rb +20 -0
  74. data/lib/jasmine/headless/coffee_template.rb +36 -0
  75. data/lib/jasmine/headless/command_line.rb +31 -0
  76. data/lib/jasmine/headless/css_template.rb +19 -0
  77. data/lib/jasmine/headless/errors.rb +16 -0
  78. data/lib/jasmine/headless/file_checker.rb +25 -0
  79. data/lib/jasmine/headless/files_list.rb +332 -0
  80. data/lib/jasmine/headless/js_template.rb +23 -0
  81. data/lib/jasmine/headless/jst_template.rb +15 -0
  82. data/lib/jasmine/headless/nil_template.rb +14 -0
  83. data/lib/jasmine/headless/options.rb +206 -0
  84. data/lib/jasmine/headless/railtie.rb +12 -0
  85. data/lib/jasmine/headless/report.rb +81 -0
  86. data/lib/jasmine/headless/report_message.rb +12 -0
  87. data/lib/jasmine/headless/report_message/console.rb +18 -0
  88. data/lib/jasmine/headless/report_message/error.rb +20 -0
  89. data/lib/jasmine/headless/report_message/fail.rb +5 -0
  90. data/lib/jasmine/headless/report_message/pass.rb +5 -0
  91. data/lib/jasmine/headless/report_message/seed.rb +14 -0
  92. data/lib/jasmine/headless/report_message/spec.rb +28 -0
  93. data/lib/jasmine/headless/report_message/total.rb +31 -0
  94. data/lib/jasmine/headless/runner.rb +264 -0
  95. data/lib/jasmine/headless/spec_file_analyzer.rb +44 -0
  96. data/lib/jasmine/headless/task.rb +39 -0
  97. data/lib/jasmine/headless/template_writer.rb +65 -0
  98. data/lib/jasmine/headless/unique_asset_list.rb +16 -0
  99. data/lib/jasmine/headless/version.rb +5 -0
  100. data/lib/qt/qmake.rb +155 -0
  101. data/script/gemfile +11 -0
  102. data/script/hooks/post-commit +4 -0
  103. data/script/hooks/pre-commit +15 -0
  104. data/script/initialize-environment +35 -0
  105. data/script/install-git-hooks +6 -0
  106. data/skel/template.html.erb +77 -0
  107. data/spec/files/UTF-8-test.txt +0 -0
  108. data/spec/integration/randomization_spec.rb +13 -0
  109. data/spec/integration/specify_runner_file_spec.rb +22 -0
  110. data/spec/integration/sprockets_spec.rb +23 -0
  111. data/spec/jasmine/click_button/click_button.js +5 -0
  112. data/spec/jasmine/click_button/click_button.yml +12 -0
  113. data/spec/jasmine/click_button/click_button_spec.js +11 -0
  114. data/spec/jasmine/coffeescript_error/coffeescript_error.yml +10 -0
  115. data/spec/jasmine/coffeescript_error/spec.coffee +2 -0
  116. data/spec/jasmine/coffeescript_error/src.coffee +2 -0
  117. data/spec/jasmine/console_log/console_log.js +1 -0
  118. data/spec/jasmine/console_log/console_log.yml +10 -0
  119. data/spec/jasmine/console_log/console_log_spec.js +7 -0
  120. data/spec/jasmine/failure/failure.js +1 -0
  121. data/spec/jasmine/failure/failure.yml +9 -0
  122. data/spec/jasmine/failure/failure_spec.js +6 -0
  123. data/spec/jasmine/filtered_failure/failure_spec.js +6 -0
  124. data/spec/jasmine/filtered_failure/filtered_failure.yml +10 -0
  125. data/spec/jasmine/filtered_failure/src.js +0 -0
  126. data/spec/jasmine/filtered_failure/success_spec.js +6 -0
  127. data/spec/jasmine/filtered_success/filtered_success.yml +10 -0
  128. data/spec/jasmine/filtered_success/src.js +0 -0
  129. data/spec/jasmine/filtered_success/success_one_spec.js +6 -0
  130. data/spec/jasmine/filtered_success/success_other_file.js +7 -0
  131. data/spec/jasmine/filtered_success/success_two_spec.js +6 -0
  132. data/spec/jasmine/filtered_success_with_console/filtered_success.yml +10 -0
  133. data/spec/jasmine/filtered_success_with_console/src.js +0 -0
  134. data/spec/jasmine/filtered_success_with_console/success_one_spec.js +7 -0
  135. data/spec/jasmine/filtered_success_with_console/success_two_spec.js +6 -0
  136. data/spec/jasmine/leave_page/leave_page.js +4 -0
  137. data/spec/jasmine/leave_page/leave_page.yml +9 -0
  138. data/spec/jasmine/leave_page/leave_page_spec.js +11 -0
  139. data/spec/jasmine/noisy/file.js.erb +0 -0
  140. data/spec/jasmine/noisy/noisy.yml +8 -0
  141. data/spec/jasmine/noisy/other_file.js +2 -0
  142. data/spec/jasmine/runner_out_in_jasmine_yml/jasmine.yml +11 -0
  143. data/spec/jasmine/runner_out_in_jasmine_yml/test.js +2 -0
  144. data/spec/jasmine/runner_out_in_jasmine_yml/test_spec.coffee +4 -0
  145. data/spec/jasmine/success/success.js +1 -0
  146. data/spec/jasmine/success/success.yml +9 -0
  147. data/spec/jasmine/success/success_spec.js +6 -0
  148. data/spec/jasmine/success_with_error/success_with_error.js +3 -0
  149. data/spec/jasmine/success_with_error/success_with_error.yml +9 -0
  150. data/spec/jasmine/success_with_error/success_with_error_spec.js +6 -0
  151. data/spec/jasmine/two_files_from_src_files/app/app-file.js +0 -0
  152. data/spec/jasmine/two_files_from_src_files/app/app.js +2 -0
  153. data/spec/jasmine/two_files_from_src_files/jasmine.yml +7 -0
  154. data/spec/jasmine/two_files_from_src_files/vendor/vendor-file.js +0 -0
  155. data/spec/jasmine/two_files_from_src_files/vendor/vendor.js +2 -0
  156. data/spec/jasmine/two_spec_files_same_basename/jasmine.yml +6 -0
  157. data/spec/jasmine/two_spec_files_same_basename/spec.coffee +4 -0
  158. data/spec/jasmine/two_spec_files_same_basename/spec.js +6 -0
  159. data/spec/jasmine/window_prompt/source.js +2 -0
  160. data/spec/jasmine/window_prompt/window_prompt.yml +4 -0
  161. data/spec/jasmine/with_sprockets_includes/assets/application.js.erb +2 -0
  162. data/spec/jasmine/with_sprockets_includes/assets/things/code.js +6 -0
  163. data/spec/jasmine/with_sprockets_includes/assets/things/jquery.string.js +0 -0
  164. data/spec/jasmine/with_sprockets_includes/assets/things/required.js +3 -0
  165. data/spec/jasmine/with_sprockets_includes/assets/things/subcode/more_code.js +2 -0
  166. data/spec/jasmine/with_sprockets_includes/assets/things/templates/that.jst.ejs +1 -0
  167. data/spec/jasmine/with_sprockets_includes/assets/things/templates/this.jst +2 -0
  168. data/spec/jasmine/with_sprockets_includes/spec/spec_helper.js +1 -0
  169. data/spec/jasmine/with_sprockets_includes/spec/things/code_spec.js +9 -0
  170. data/spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml +12 -0
  171. data/spec/javascripts/console.log_spec.coffee +15 -0
  172. data/spec/javascripts/headless_reporter_result_spec.coffee +30 -0
  173. data/spec/javascripts/helpers/spec_helper.coffee +2 -0
  174. data/spec/javascripts/jasmine-extensions_spec.coffee +80 -0
  175. data/spec/javascripts/jasmine.HeadlessReporter.ConsoleBase_spec.coffee +35 -0
  176. data/spec/javascripts/jasmine.HeadlessReporter.Console_spec.coffee +3 -0
  177. data/spec/javascripts/jasmine.HeadlessReporter.Tap_spec.coffee +19 -0
  178. data/spec/javascripts/jasmine.HeadlessReporter_spec.coffee +27 -0
  179. data/spec/javascripts/support/jasmine.yml +9 -0
  180. data/spec/lib/jasmine/headless/cacheable_action_spec.rb +122 -0
  181. data/spec/lib/jasmine/headless/coffee_script_cache_spec.rb +21 -0
  182. data/spec/lib/jasmine/headless/coffee_template_spec.rb +55 -0
  183. data/spec/lib/jasmine/headless/css_template_spec.rb +25 -0
  184. data/spec/lib/jasmine/headless/file_checker_spec.rb +41 -0
  185. data/spec/lib/jasmine/headless/files_list_spec.rb +194 -0
  186. data/spec/lib/jasmine/headless/js_template_spec.rb +31 -0
  187. data/spec/lib/jasmine/headless/jst_template_spec.rb +21 -0
  188. data/spec/lib/jasmine/headless/nil_template_spec.rb +31 -0
  189. data/spec/lib/jasmine/headless/options_spec.rb +194 -0
  190. data/spec/lib/jasmine/headless/report_message/seed_spec.rb +18 -0
  191. data/spec/lib/jasmine/headless/report_message/spec_spec.rb +20 -0
  192. data/spec/lib/jasmine/headless/report_spec.rb +95 -0
  193. data/spec/lib/jasmine/headless/runner_spec.rb +247 -0
  194. data/spec/lib/jasmine/headless/spec_file_analyzer_spec.rb +68 -0
  195. data/spec/lib/jasmine/headless/task_spec.rb +92 -0
  196. data/spec/lib/jasmine/headless/template_writer_spec.rb +92 -0
  197. data/spec/lib/jasmine/headless/unique_asset_list_spec.rb +22 -0
  198. data/spec/lib/jasmine/headless_spec.rb +38 -0
  199. data/spec/lib/qt/qmake_spec.rb +142 -0
  200. data/spec/skel/template.html.erb_spec.rb +8 -0
  201. data/spec/spec_helper.rb +113 -0
  202. data/vendor/assets/coffeescripts/headless_reporter_result.coffee +49 -0
  203. data/vendor/assets/coffeescripts/prolog.coffee +100 -0
  204. data/vendor/assets/javascripts/beautify-html.js +463 -0
  205. data/vendor/assets/javascripts/headless_reporter_result.js +79 -0
  206. data/vendor/assets/javascripts/intense.coffee +28 -0
  207. data/vendor/assets/javascripts/jasmine-extensions.coffee +97 -0
  208. data/vendor/assets/javascripts/jasmine.HeadlessReporter.Console.coffee +8 -0
  209. data/vendor/assets/javascripts/jasmine.HeadlessReporter.ConsoleBase.coffee +92 -0
  210. data/vendor/assets/javascripts/jasmine.HeadlessReporter.File.coffee +24 -0
  211. data/vendor/assets/javascripts/jasmine.HeadlessReporter.Tap.coffee +28 -0
  212. data/vendor/assets/javascripts/jasmine.HeadlessReporter.Verbose.coffee +64 -0
  213. data/vendor/assets/javascripts/jasmine.HeadlessReporter.coffee +58 -0
  214. data/vendor/assets/javascripts/jsDump.js +209 -0
  215. data/vendor/assets/javascripts/prolog.js +108 -0
  216. metadata +347 -0
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'skel/template.html.erb' do
4
+ describe 'reporters' do
5
+
6
+ end
7
+ end
8
+
@@ -0,0 +1,113 @@
1
+ if ENV['COVERAGE']
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
5
+
6
+ if ENV['PROFILE']
7
+ require 'perftools'
8
+ PerfTools::CpuProfiler.start("/tmp/jhw-profile")
9
+ end
10
+
11
+ require 'jasmine-headless-webkit'
12
+ require 'fakefs/spec_helpers'
13
+
14
+ RSpec.configure do |c|
15
+ c.mock_with :mocha
16
+ c.backtrace_clean_patterns = []
17
+
18
+ c.before(:each) do
19
+ Jasmine::Headless::CacheableAction.enabled = false
20
+ Jasmine::Headless::FilesList.reset!
21
+ end
22
+
23
+ c.before(:each, :type => :integration) do
24
+ let(:report) { 'spec/report.txt' }
25
+
26
+ before do
27
+ FileUtils.rm_f report
28
+ end
29
+
30
+ after do
31
+ FileUtils.rm_f report
32
+ end
33
+ end
34
+ end
35
+
36
+ specrunner = 'ext/jasmine-webkit-specrunner/jasmine-webkit-specrunner'
37
+
38
+ if !File.file?(specrunner)
39
+ Dir.chdir File.split(specrunner).first do
40
+ system %{ruby extconf.rb}
41
+ end
42
+ end
43
+
44
+ class FakeFS::File
45
+ class << self
46
+ def fnmatch?(pattern, file)
47
+ RealFile.fnmatch?(pattern, file)
48
+ end
49
+ end
50
+
51
+ class Stat
52
+ def file?
53
+ File.file?(@file)
54
+ end
55
+ end
56
+ end
57
+
58
+ module RSpec::Matchers
59
+ define :be_a_report_containing do |total, failed, used_console|
60
+ match do |filename|
61
+ report(filename)
62
+ report.total.should == total
63
+ report.failed.should == failed
64
+ report.has_used_console?.should == used_console
65
+ true
66
+ end
67
+
68
+ failure_message_for_should do |filename|
69
+ "expected #{filename} to be a report containing (#{total}, #{failed}, #{used_console.inspect})"
70
+ end
71
+
72
+ def report(filename = nil)
73
+ @report ||= Jasmine::Headless::Report.load(filename)
74
+ end
75
+ end
76
+
77
+ define :contain_a_failing_spec do |*parts|
78
+ match do |filename|
79
+ report(filename).should have_failed_on(parts.join(" "))
80
+ end
81
+
82
+ def report(filename)
83
+ @report ||= Jasmine::Headless::Report.load(filename)
84
+ end
85
+ end
86
+
87
+ define :be_a_file do
88
+ match do |file|
89
+ File.file?(file)
90
+ end
91
+ end
92
+
93
+ define :contain_in_order_in_file_list do |*files|
94
+ match do |lines|
95
+ file_list = files.dup
96
+
97
+ lines.each do |line|
98
+ next if !file_list.first
99
+
100
+ if line[file_list.first]
101
+ file_list.shift
102
+ end
103
+ end
104
+
105
+ file_list.length == 0
106
+ end
107
+
108
+ failure_message_for_should do |lines|
109
+ %{expected\n#{lines.join("\n")}\nto contain the following files, in order:\n#{files.join("\n")}}
110
+ end
111
+ end
112
+ end
113
+
@@ -0,0 +1,49 @@
1
+ # Try to get the line number of a failed spec
2
+ class window.HeadlessReporterResult
3
+ constructor: (@name, @splitName) ->
4
+ @results = []
5
+
6
+ addResult: (message) ->
7
+ @results.push(message)
8
+
9
+ toString: ->
10
+ output = "\n" + @name.foreground('red')
11
+ bestChoice = HeadlessReporterResult.findSpecLine(@splitName)
12
+ output += " (#{bestChoice.file}:#{bestChoice.lineNumber})".foreground('blue') if bestChoice.file
13
+
14
+ for result in @results
15
+ line = result.message.foreground('red')
16
+ if result.lineNumber
17
+ line += " (line ~#{bestChoice.lineNumber + result.lineNumber})".foreground('red').bright()
18
+ output += "\n #{line}"
19
+
20
+ if result.line?
21
+ output += "\n #{result.line}".foreground('yellow')
22
+
23
+ output
24
+
25
+ @findSpecLine: (splitName) ->
26
+ bestChoice = { accuracy: 0, file: null, lineNumber: null }
27
+
28
+ for file, lines of HeadlessReporterResult.specLineNumbers
29
+ index = 0
30
+ lineNumber = 0
31
+ while newLineNumberInfo = lines[splitName[index]]
32
+ if newLineNumberInfo.length == 0
33
+ lineNumber = newLineNumberInfo[0]
34
+ else
35
+ lastLine = null
36
+ for line in newLineNumberInfo
37
+ lastLine = line
38
+ break if line > lineNumber
39
+
40
+ lineNumber = lastLine
41
+
42
+ index++
43
+
44
+ if index > bestChoice.accuracy
45
+ bestChoice = { accuracy: index, file: file, lineNumber: lineNumber }
46
+
47
+ break if index == splitName.length
48
+
49
+ bestChoice
@@ -0,0 +1,100 @@
1
+ if window.JHW
2
+ window.console =
3
+ log: (data) ->
4
+ if typeof(jQuery) != 'undefined' && data instanceof jQuery
5
+ JHW.log(style_html($("<div />").append(data.clone()).html(), { indent_size: 2 }))
6
+ else
7
+ useJsDump = true
8
+
9
+ try
10
+ if typeof data.toJSON == 'function'
11
+ JHW.log("JSON: #{JSON.stringify(data, null, 2)}")
12
+ useJsDump = false
13
+ catch e
14
+
15
+ if useJsDump
16
+ dump = jsDump.doParse(data)
17
+ if dump.indexOf("\n") == -1
18
+ JHW.log(dump)
19
+ else
20
+ JHW.log("jsDump: #{dump}")
21
+
22
+ pp: (data) ->
23
+ JHW.log(if jasmine then jasmine.pp(data) else console.log(data))
24
+
25
+ peek: (data) ->
26
+ console.log(data)
27
+ data
28
+
29
+ puts = (message) ->
30
+ JHW.print('stdout', message + "\n")
31
+
32
+ warn = (message) ->
33
+ puts(message) if !JHW.isQuiet()
34
+
35
+ # handle unloading
36
+ window.onbeforeunload = (e) ->
37
+ e = e || window.event
38
+
39
+ JHW.hasError()
40
+ warn "The code tried to leave the test page. Check for unhandled form submits and link clicks."
41
+
42
+ e.returnValue = 'string' if e
43
+
44
+ return 'string'
45
+
46
+ # script errors
47
+ JHW._hasErrors = false
48
+ JHW._handleError = (message, lineNumber, sourceURL) ->
49
+ JHW.print('stderr', message + "\n")
50
+ JHW._hasErrors = true
51
+ false
52
+
53
+ # dialogs
54
+ window.confirm = ->
55
+ warn "#{"[confirm]".foreground('red')} You should mock window.confirm. Returning true."
56
+
57
+ true
58
+
59
+ window.prompt = ->
60
+ warn "#{"[prompt]".foreground('red')} You should mock window.prompt. Returning true."
61
+
62
+ true
63
+
64
+ window.alert = (message) ->
65
+ warn "[alert] ".foreground('red') + message
66
+
67
+ # color support
68
+ JHW._setColors = (useColors) -> Intense.useColors = useColors
69
+
70
+ # console.log support
71
+ JHW._usedConsole = false
72
+ JHW.log = (msg) ->
73
+ JHW.hasUsedConsole()
74
+
75
+ for reporter in jasmine.getEnv().reporter.subReporters_
76
+ reporter.consoleLogUsed(msg) if reporter.consoleLogUsed?
77
+
78
+ JHW._usedConsole = true
79
+
80
+ puts msg
81
+
82
+ JHW.createCoffeeScriptFileException = (e) ->
83
+ if e and e.sourceURL
84
+ filename = e.sourceURL.split('/').pop()
85
+
86
+ e =
87
+ name: e.name
88
+ message: e.message
89
+ sourceURL: e.sourceURL
90
+ lineNumber: e.line
91
+
92
+ if window.CoffeeScriptToFilename and realFilename = window.CoffeeScriptToFilename[filename]
93
+ e.sourceURL = realFilename
94
+ e.lineNumber = "~" + String(e.line)
95
+
96
+ e
97
+
98
+ window.CoffeeScriptToFilename = {}
99
+ window.CSTF = window.CoffeeScriptToFilename
100
+
@@ -0,0 +1,463 @@
1
+ /*
2
+
3
+ Style HTML
4
+ ---------------
5
+
6
+ Written by Nochum Sossonko, (nsossonko@hotmail.com)
7
+
8
+ Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
9
+ http://jsbeautifier.org/
10
+
11
+
12
+ You are free to use this in any way you want, in case you find this useful or working for you.
13
+
14
+ Usage:
15
+ style_html(html_source);
16
+
17
+ style_html(html_source, options);
18
+
19
+ The options are:
20
+ indent_size (default 4) — indentation size,
21
+ indent_char (default space) — character to indent with,
22
+ max_char (default 70) - maximum amount of characters per line,
23
+ brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
24
+ put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
25
+
26
+ e.g.
27
+
28
+ style_html(html_source, {
29
+ 'indent_size': 2,
30
+ 'indent_char': ' ',
31
+ 'max_char': 78,
32
+ 'brace_style': 'expand'
33
+ });
34
+ */
35
+
36
+ function style_html(html_source, options) {
37
+ //Wrapper function to invoke all the necessary constructors and deal with the output.
38
+
39
+ var multi_parser,
40
+ indent_size,
41
+ indent_character,
42
+ max_char,
43
+ brace_style;
44
+
45
+ options = options || {};
46
+ indent_size = options.indent_size || 4;
47
+ indent_character = options.indent_char || ' ';
48
+ brace_style = options.brace_style || 'collapse';
49
+ max_char = options.max_char || '70';
50
+
51
+ function Parser() {
52
+
53
+ this.pos = 0; //Parser position
54
+ this.token = '';
55
+ this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
56
+ this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
57
+ parent: 'parent1',
58
+ parentcount: 1,
59
+ parent1: ''
60
+ };
61
+ this.tag_type = '';
62
+ this.token_text = this.last_token = this.last_text = this.token_type = '';
63
+
64
+ this.Utils = { //Uilities made available to the various functions
65
+ whitespace: "\n\r\t ".split(''),
66
+ single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','), //all the single tags for HTML
67
+ extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
68
+ in_array: function (what, arr) {
69
+ for (var i=0; i<arr.length; i++) {
70
+ if (what === arr[i]) {
71
+ return true;
72
+ }
73
+ }
74
+ return false;
75
+ }
76
+ }
77
+
78
+ this.get_content = function () { //function to capture regular content between tags
79
+
80
+ var input_char = '';
81
+ var content = [];
82
+ var space = false; //if a space is needed
83
+ while (this.input.charAt(this.pos) !== '<') {
84
+ if (this.pos >= this.input.length) {
85
+ return content.length?content.join(''):['', 'TK_EOF'];
86
+ }
87
+
88
+ input_char = this.input.charAt(this.pos);
89
+ this.pos++;
90
+ this.line_char_count++;
91
+
92
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
93
+ if (content.length) {
94
+ space = true;
95
+ }
96
+ this.line_char_count--;
97
+ continue; //don't want to insert unnecessary space
98
+ }
99
+ else if (space) {
100
+ if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
101
+ content.push('\n');
102
+ for (var i=0; i<this.indent_level; i++) {
103
+ content.push(this.indent_string);
104
+ }
105
+ this.line_char_count = 0;
106
+ }
107
+ else{
108
+ content.push(' ');
109
+ this.line_char_count++;
110
+ }
111
+ space = false;
112
+ }
113
+ content.push(input_char); //letter at-a-time (or string) inserted to an array
114
+ }
115
+ return content.length?content.join(''):'';
116
+ }
117
+
118
+ this.get_script = function () { //get the full content of a script to pass to js_beautify
119
+
120
+ var input_char = '';
121
+ var content = [];
122
+ var reg_match = new RegExp('\<\/script' + '\>', 'igm');
123
+ reg_match.lastIndex = this.pos;
124
+ var reg_array = reg_match.exec(this.input);
125
+ var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
126
+ while(this.pos < end_script) { //get everything in between the script tags
127
+ if (this.pos >= this.input.length) {
128
+ return content.length?content.join(''):['', 'TK_EOF'];
129
+ }
130
+
131
+ input_char = this.input.charAt(this.pos);
132
+ this.pos++;
133
+
134
+ content.push(input_char);
135
+ }
136
+ return content.length?content.join(''):''; //we might not have any content at all
137
+ }
138
+
139
+ this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
140
+ if (this.tags[tag + 'count']) { //check for the existence of this tag type
141
+ this.tags[tag + 'count']++;
142
+ this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
143
+ }
144
+ else { //otherwise initialize this tag type
145
+ this.tags[tag + 'count'] = 1;
146
+ this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
147
+ }
148
+ this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
149
+ this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
150
+ }
151
+
152
+ this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
153
+ if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
154
+ var temp_parent = this.tags.parent; //check to see if it's a closable tag.
155
+ while (temp_parent) { //till we reach '' (the initial value);
156
+ if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
157
+ break;
158
+ }
159
+ temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
160
+ }
161
+ if (temp_parent) { //if we caught something
162
+ this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
163
+ this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
164
+ }
165
+ delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
166
+ delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
167
+ if (this.tags[tag + 'count'] == 1) {
168
+ delete this.tags[tag + 'count'];
169
+ }
170
+ else {
171
+ this.tags[tag + 'count']--;
172
+ }
173
+ }
174
+ }
175
+
176
+ this.get_tag = function () { //function to get a full tag and parse its type
177
+ var input_char = '';
178
+ var content = [];
179
+ var space = false;
180
+
181
+ do {
182
+ if (this.pos >= this.input.length) {
183
+ return content.length?content.join(''):['', 'TK_EOF'];
184
+ }
185
+
186
+ input_char = this.input.charAt(this.pos);
187
+ this.pos++;
188
+ this.line_char_count++;
189
+
190
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
191
+ space = true;
192
+ this.line_char_count--;
193
+ continue;
194
+ }
195
+
196
+ if (input_char === "'" || input_char === '"') {
197
+ if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
198
+ input_char += this.get_unformatted(input_char);
199
+ space = true;
200
+ }
201
+ }
202
+
203
+ if (input_char === '=') { //no space before =
204
+ space = false;
205
+ }
206
+
207
+ if (content.length && content[content.length-1] !== '=' && input_char !== '>'
208
+ && space) { //no space after = or before >
209
+ if (this.line_char_count >= this.max_char) {
210
+ this.print_newline(false, content);
211
+ this.line_char_count = 0;
212
+ }
213
+ else {
214
+ content.push(' ');
215
+ this.line_char_count++;
216
+ }
217
+ space = false;
218
+ }
219
+ content.push(input_char); //inserts character at-a-time (or string)
220
+ } while (input_char !== '>');
221
+
222
+ var tag_complete = content.join('');
223
+ var tag_index;
224
+ if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
225
+ tag_index = tag_complete.indexOf(' ');
226
+ }
227
+ else { //otherwise go with the tag ending
228
+ tag_index = tag_complete.indexOf('>');
229
+ }
230
+ var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
231
+ if (tag_complete.charAt(tag_complete.length-2) === '/' ||
232
+ this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
233
+ this.tag_type = 'SINGLE';
234
+ }
235
+ else if (tag_check === 'script') { //for later script handling
236
+ this.record_tag(tag_check);
237
+ this.tag_type = 'SCRIPT';
238
+ }
239
+ else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
240
+ this.record_tag(tag_check);
241
+ this.tag_type = 'STYLE';
242
+ }
243
+ else if (tag_check === 'a') { // do not reformat the <a> links
244
+ var comment = this.get_unformatted('</a>', tag_complete); //...delegate to get_unformatted function
245
+ content.push(comment);
246
+ this.tag_type = 'SINGLE';
247
+ }
248
+ else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
249
+ if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
250
+ if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
251
+ var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
252
+ content.push(comment);
253
+ }
254
+ this.tag_type = 'START';
255
+ }
256
+ else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
257
+ this.tag_type = 'END';
258
+ this.unindent();
259
+ }
260
+ else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
261
+ var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
262
+ content.push(comment);
263
+ this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
264
+ }
265
+ else {
266
+ var comment = this.get_unformatted('-->', tag_complete);
267
+ content.push(comment);
268
+ this.tag_type = 'SINGLE';
269
+ }
270
+ }
271
+ else {
272
+ if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
273
+ this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
274
+ this.tag_type = 'END';
275
+ }
276
+ else { //otherwise it's a start-tag
277
+ this.record_tag(tag_check); //push it on the tag stack
278
+ this.tag_type = 'START';
279
+ }
280
+ if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
281
+ this.print_newline(true, this.output);
282
+ }
283
+ }
284
+ return content.join(''); //returns fully formatted tag
285
+ }
286
+
287
+ this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
288
+
289
+ if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
290
+ return '';
291
+ }
292
+ var input_char = '';
293
+ var content = '';
294
+ var space = true;
295
+ do {
296
+
297
+ if (this.pos >= this.input.length) {
298
+ return content;
299
+ }
300
+
301
+ input_char = this.input.charAt(this.pos);
302
+ this.pos++
303
+
304
+ if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
305
+ if (!space) {
306
+ this.line_char_count--;
307
+ continue;
308
+ }
309
+ if (input_char === '\n' || input_char === '\r') {
310
+ content += '\n';
311
+ for (var i=0; i<this.indent_level; i++) {
312
+ content += this.indent_string;
313
+ }
314
+ space = false; //...and make sure other indentation is erased
315
+ this.line_char_count = 0;
316
+ continue;
317
+ }
318
+ }
319
+ content += input_char;
320
+ this.line_char_count++;
321
+ space = true;
322
+
323
+
324
+ } while (content.indexOf(delimiter) == -1);
325
+ return content;
326
+ }
327
+
328
+ this.get_token = function () { //initial handler for token-retrieval
329
+ var token;
330
+
331
+ if (this.last_token === 'TK_TAG_SCRIPT') { //check if we need to format javascript
332
+ var temp_token = this.get_script();
333
+ if (typeof temp_token !== 'string') {
334
+ return temp_token;
335
+ }
336
+ token = js_beautify(temp_token.replace(/^[\r\n]+/, ''), {
337
+ 'indent_size': this.indent_size,
338
+ 'indent_char': this.indent_character,
339
+ 'brace_style': this.brace_style
340
+ }); //call the JS Beautifier
341
+ return [token, 'TK_CONTENT'];
342
+ }
343
+ if (this.current_mode === 'CONTENT') {
344
+ token = this.get_content();
345
+ if (typeof token !== 'string') {
346
+ return token;
347
+ }
348
+ else {
349
+ return [token, 'TK_CONTENT'];
350
+ }
351
+ }
352
+
353
+ if (this.current_mode === 'TAG') {
354
+ token = this.get_tag();
355
+ if (typeof token !== 'string') {
356
+ return token;
357
+ }
358
+ else {
359
+ var tag_name_type = 'TK_TAG_' + this.tag_type;
360
+ return [token, tag_name_type];
361
+ }
362
+ }
363
+ }
364
+
365
+ this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions
366
+
367
+ this.input = js_source || ''; //gets the input for the Parser
368
+ this.output = [];
369
+ this.indent_character = indent_character;
370
+ this.indent_string = '';
371
+ this.indent_size = indent_size;
372
+ this.brace_style = brace_style;
373
+ this.indent_level = 0;
374
+ this.max_char = max_char;
375
+ this.line_char_count = 0; //count to see if max_char was exceeded
376
+
377
+ for (var i=0; i<this.indent_size; i++) {
378
+ this.indent_string += this.indent_character;
379
+ }
380
+
381
+ this.print_newline = function (ignore, arr) {
382
+ this.line_char_count = 0;
383
+ if (!arr || !arr.length) {
384
+ return;
385
+ }
386
+ if (!ignore) { //we might want the extra line
387
+ while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
388
+ arr.pop();
389
+ }
390
+ }
391
+ arr.push('\n');
392
+ for (var i=0; i<this.indent_level; i++) {
393
+ arr.push(this.indent_string);
394
+ }
395
+ }
396
+
397
+ this.print_token = function (text) {
398
+ this.output.push(text);
399
+ }
400
+
401
+ this.indent = function () {
402
+ this.indent_level++;
403
+ }
404
+
405
+ this.unindent = function () {
406
+ if (this.indent_level > 0) {
407
+ this.indent_level--;
408
+ }
409
+ }
410
+ }
411
+ return this;
412
+ }
413
+
414
+ /*_____________________--------------------_____________________*/
415
+
416
+ multi_parser = new Parser(); //wrapping functions Parser
417
+ multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
418
+
419
+ while (true) {
420
+ var t = multi_parser.get_token();
421
+ multi_parser.token_text = t[0];
422
+ multi_parser.token_type = t[1];
423
+
424
+ if (multi_parser.token_type === 'TK_EOF') {
425
+ break;
426
+ }
427
+
428
+ switch (multi_parser.token_type) {
429
+ case 'TK_TAG_START':
430
+ case 'TK_TAG_STYLE':
431
+ multi_parser.print_newline(false, multi_parser.output);
432
+ multi_parser.print_token(multi_parser.token_text);
433
+ multi_parser.indent();
434
+ multi_parser.current_mode = 'CONTENT';
435
+ break;
436
+ case 'TK_TAG_SCRIPT':
437
+ multi_parser.print_newline(false, multi_parser.output);
438
+ multi_parser.print_token(multi_parser.token_text);
439
+ multi_parser.current_mode = 'CONTENT';
440
+ break;
441
+ case 'TK_TAG_END':
442
+ multi_parser.print_newline(true, multi_parser.output);
443
+ multi_parser.print_token(multi_parser.token_text);
444
+ multi_parser.current_mode = 'CONTENT';
445
+ break;
446
+ case 'TK_TAG_SINGLE':
447
+ multi_parser.print_newline(false, multi_parser.output);
448
+ multi_parser.print_token(multi_parser.token_text);
449
+ multi_parser.current_mode = 'CONTENT';
450
+ break;
451
+ case 'TK_CONTENT':
452
+ if (multi_parser.token_text !== '') {
453
+ multi_parser.print_newline(false, multi_parser.output);
454
+ multi_parser.print_token(multi_parser.token_text);
455
+ }
456
+ multi_parser.current_mode = 'TAG';
457
+ break;
458
+ }
459
+ multi_parser.last_token = multi_parser.token_type;
460
+ multi_parser.last_text = multi_parser.token_text;
461
+ }
462
+ return multi_parser.output.join('');
463
+ }