1
0

angular.rb 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. require 'yajl/json_gem'
  2. module Docs
  3. class Angular < UrlScraper
  4. self.type = 'angular'
  5. self.links = {
  6. home: 'https://angular.dev/',
  7. code: 'https://github.com/angular/angular'
  8. }
  9. self.base_url = 'https://angular.io/'
  10. self.root_path = 'docs'
  11. options[:max_image_size] = 256_000
  12. options[:attribution] = <<-HTML
  13. Super-powered by Google &copy;2010&ndash;2025.<br />
  14. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
  15. HTML
  16. options[:follow_links] = false
  17. options[:only_patterns] = [/\Aguide/, /\Aapi/, /\Acli/]
  18. options[:fix_urls_before_parse] = ->(url) do
  19. url.sub! %r{\Aguide/}, '/guide/'
  20. url.sub! %r{\Aapi/}, '/api/'
  21. url.sub! %r{\cli/}, '/cli/'
  22. url.sub! %r{\Agenerated/}, '/generated/'
  23. url
  24. end
  25. module JsonNavigation
  26. private
  27. def initial_urls
  28. initial_urls = []
  29. Request.run "#{self.class.base_url}generated/navigation.json" do |response|
  30. data = JSON.parse(response.body)
  31. dig = ->(entry) do
  32. initial_urls << url_for("generated/docs/#{entry['url']}.json") if entry['url'] && entry['url'] != 'api'
  33. entry['children'].each(&dig) if entry['children']
  34. end
  35. data['SideNav'].each(&dig)
  36. end
  37. Request.run "#{self.class.base_url}generated/docs/api/api-list.json" do |response|
  38. data = JSON.parse(response.body)
  39. dig = ->(entry) do
  40. initial_urls << url_for("generated/docs/#{entry['path']}.json") if entry['path']
  41. initial_urls << url_for("generated/docs/api/#{entry['name']}.json") if entry['name'] && !entry['path']
  42. entry['items'].each(&dig) if entry['items']
  43. end
  44. data.each(&dig)
  45. end
  46. initial_urls
  47. end
  48. def handle_response(response)
  49. if response.mime_type.include?('json')
  50. begin
  51. json = JSON.parse(response.body)
  52. response.options[:response_body] = json['contents']
  53. response.url.path = response.url.path.gsub(/generated\/docs\/.*/, json['id'])
  54. response.effective_url.path = response.effective_url.path.gsub(/generated\/docs\/.*/, json['id'])
  55. rescue JSON::ParserError
  56. response.options[:response_body] = ''
  57. end
  58. response.headers['Content-Type'] = 'text/html'
  59. end
  60. super
  61. end
  62. end
  63. module Since12
  64. def url_for(path)
  65. # See encodeToLowercase im aio/tools/transforms/angular-base-package/processors/disambiguateDocPaths.js
  66. path = path.gsub(/[A-Z_]/) {|s| s.downcase + '_'}
  67. super
  68. end
  69. include Docs::Angular::JsonNavigation
  70. end
  71. module Since18
  72. def self.handle_redirects(version)
  73. lambda do |url|
  74. url.sub! '/guide/templates/reference-variables', '/guide/templates/variables#template-reference-variables'
  75. url.sub! '/guide/signals/inputs', '/guide/components/inputs'
  76. url.sub! '/guide/defer', '/guide/templates/defer'
  77. url.sub! '/guide/templates/class-binding', '/guide/templates/binding#css-class-and-style-property-bindings'
  78. url.sub! %r{/guide/components$}, '/guide/components/anatomy-of-components'
  79. url.sub! '/guide/templates/property-binding', '/guide/templates/binding#binding-dynamic-properties-and-attributes'
  80. url.sub! %r{/guide/ngmodules$}, '/guide/ngmodules/overview'
  81. url.sub! '/guide/components/importing', '/guide/components/anatomy-of-components#using-components'
  82. url.sub! '/guide/components/anatomy-of-components', '/guide/components' if version == '20'
  83. url
  84. end
  85. end
  86. end
  87. version do
  88. self.release = '21.0.3'
  89. self.base_url = 'https://angular.dev/'
  90. self.root_path = 'overview'
  91. options[:follow_links] = true
  92. options[:container] = '.docs-app-main-content'
  93. options[:fix_urls] = Since18.handle_redirects(self.version)
  94. html_filters.push 'angular/entries', 'angular/clean_html_v18'
  95. include Docs::Angular::Since18
  96. end
  97. version '20' do
  98. self.release = '20.3.15'
  99. self.base_url = 'https://v20.angular.dev/'
  100. self.root_path = 'overview'
  101. options[:follow_links] = true
  102. options[:container] = '.docs-app-main-content'
  103. options[:fix_urls] = Since18.handle_redirects(self.version)
  104. html_filters.push 'angular/entries', 'angular/clean_html_v18'
  105. include Docs::Angular::Since18
  106. end
  107. version '19' do
  108. self.release = '19.2.15'
  109. self.base_url = 'https://v19.angular.dev/'
  110. self.root_path = 'overview'
  111. options[:follow_links] = true
  112. options[:container] = '.docs-app-main-content'
  113. options[:fix_urls] = Since18.handle_redirects(self.version)
  114. html_filters.push 'angular/entries', 'angular/clean_html_v18'
  115. include Docs::Angular::Since18
  116. end
  117. version '18' do
  118. self.release = '18.2.14'
  119. self.base_url = 'https://v18.angular.dev/'
  120. self.root_path = 'overview'
  121. options[:follow_links] = true
  122. options[:container] = '.docs-app-main-content'
  123. options[:fix_urls] = Since18.handle_redirects(self.version)
  124. html_filters.push 'angular/entries', 'angular/clean_html_v18'
  125. include Docs::Angular::Since18
  126. end
  127. version '17' do
  128. self.release = '17.0.8'
  129. self.base_url = 'https://v17.angular.io/'
  130. html_filters.push 'angular/clean_html', 'angular/entries'
  131. include Docs::Angular::Since12
  132. end
  133. version '16' do
  134. self.release = '16.2.12'
  135. self.base_url = 'https://v16.angular.io/'
  136. html_filters.push 'angular/clean_html', 'angular/entries'
  137. include Docs::Angular::Since12
  138. end
  139. version '15' do
  140. self.release = '15.2.9'
  141. self.base_url = 'https://v15.angular.io/'
  142. html_filters.push 'angular/clean_html', 'angular/entries'
  143. include Docs::Angular::Since12
  144. end
  145. version '14' do
  146. self.release = '14.2.12'
  147. self.base_url = 'https://v14.angular.io/'
  148. html_filters.push 'angular/clean_html', 'angular/entries'
  149. include Docs::Angular::Since12
  150. end
  151. version '13' do
  152. self.release = '13.3.8'
  153. self.base_url = 'https://v13.angular.io/'
  154. html_filters.push 'angular/clean_html', 'angular/entries'
  155. include Docs::Angular::Since12
  156. end
  157. version '12' do
  158. self.release = '12.2.13'
  159. self.base_url = 'https://v12.angular.io/'
  160. html_filters.push 'angular/clean_html', 'angular/entries'
  161. include Docs::Angular::Since12
  162. end
  163. version '11' do
  164. self.release = '11.2.14'
  165. self.base_url = 'https://v11.angular.io/'
  166. html_filters.push 'angular/clean_html', 'angular/entries'
  167. include Docs::Angular::JsonNavigation
  168. end
  169. version '10' do
  170. self.release = '10.2.3'
  171. self.base_url = 'https://v10.angular.io/'
  172. html_filters.push 'angular/clean_html', 'angular/entries'
  173. include Docs::Angular::JsonNavigation
  174. end
  175. version '9' do
  176. self.release = '9.1.12'
  177. self.base_url = 'https://v9.angular.io/'
  178. html_filters.push 'angular/clean_html', 'angular/entries'
  179. include Docs::Angular::JsonNavigation
  180. end
  181. version '8' do
  182. self.release = '8.2.14'
  183. self.base_url = 'https://v8.angular.io/'
  184. html_filters.push 'angular/clean_html', 'angular/entries'
  185. include Docs::Angular::JsonNavigation
  186. end
  187. version '7' do
  188. self.release = '7.2.15'
  189. self.base_url = 'https://v7.angular.io/'
  190. html_filters.push 'angular/clean_html', 'angular/entries'
  191. include Docs::Angular::JsonNavigation
  192. end
  193. version '6' do
  194. self.release = '6.1.10'
  195. self.base_url = 'https://v6.angular.io/'
  196. html_filters.push 'angular/clean_html', 'angular/entries'
  197. include Docs::Angular::JsonNavigation
  198. end
  199. version '5' do
  200. self.release = '5.2.11'
  201. self.base_url = 'https://v5.angular.io/'
  202. html_filters.push 'angular/clean_html', 'angular/entries'
  203. include Docs::Angular::JsonNavigation
  204. end
  205. version '4' do
  206. self.release = '4.4.6'
  207. self.base_url = 'https://v4.angular.io/'
  208. html_filters.push 'angular/clean_html', 'angular/entries'
  209. include Docs::Angular::JsonNavigation
  210. end
  211. version '2' do
  212. self.release = '2.4.10'
  213. self.base_url = 'https://v2.angular.io/docs/ts/latest/'
  214. self.root_path = 'api/'
  215. html_filters.push 'angular/entries_v2', 'angular/clean_html_v2'
  216. stub 'api/' do
  217. base_url = URL.parse(self.base_url)
  218. capybara = load_capybara_selenium
  219. capybara.app_host = base_url.origin
  220. capybara.visit(base_url.path + 'api/')
  221. capybara.execute_script('return document.body.innerHTML')
  222. end
  223. options[:skip_patterns] = [/deprecated/, /VERSION-let/]
  224. options[:skip] = %w(
  225. index.html
  226. styleguide.html
  227. quickstart.html
  228. cheatsheet.html
  229. guide/cheatsheet.html
  230. guide/style-guide.html)
  231. options[:replace_paths] = {
  232. 'testing/index.html' => 'guide/testing.html',
  233. 'guide/glossary.html' => 'glossary.html',
  234. 'tutorial' => 'tutorial/',
  235. 'api' => 'api/'
  236. }
  237. options[:fix_urls] = -> (url) do
  238. url.sub! %r{\A(https://(?:v2\.)?angular\.io/docs/.+/)index\.html\z}, '\1'
  239. url
  240. end
  241. end
  242. def get_latest_version(opts)
  243. get_npm_version('@angular/core', opts)
  244. end
  245. private
  246. def parse(response)
  247. response.body.gsub! '<code-example', '<pre'
  248. response.body.gsub! '</code-example', '</pre'
  249. response.body.gsub! '<code-pane', '<pre'
  250. response.body.gsub! '</code-pane', '</pre'
  251. response.body.gsub! '<live-example></live-example>', 'live example'
  252. response.body.gsub! '<live-example', '<span'
  253. response.body.gsub! '</live-example', '</span'
  254. super
  255. end
  256. end
  257. end