danger-wcc 0.0.3 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +22 -15
  3. data/danger-wcc.gemspec +3 -3
  4. data/lib/version.rb +1 -1
  5. data/lib/wcc/commit_lint.rb +2 -1
  6. data/lib/wcc/commit_lint/commit_check.rb +0 -1
  7. data/lib/wcc/commit_lint/empty_line_check.rb +0 -1
  8. data/lib/wcc/commit_lint/subject_cap_check.rb +0 -1
  9. data/lib/wcc/commit_lint/subject_length_check.rb +0 -1
  10. data/lib/wcc/commit_lint/subject_period_check.rb +0 -1
  11. data/lib/wcc/commit_lint/subject_words_check.rb +0 -1
  12. data/lib/wcc/defaults.reek +8 -8
  13. data/lib/wcc/dependencies.rb +100 -0
  14. data/lib/wcc/jshint.rb +2 -2
  15. data/lib/wcc/plugin.rb +30 -12
  16. data/lib/wcc/reek.rb +2 -2
  17. data/lib/wcc/rubocop_exceptions.rb +13 -8
  18. data/lib/wcc/todos.rb +5 -4
  19. data/lib/wcc/util/yarn_info.rb +84 -0
  20. data/lib/wcc/utils.rb +17 -5
  21. data/lib/wcc/yarn_deduplicate.rb +72 -0
  22. data/spec/fixtures/dependencies/package.json +112 -0
  23. data/spec/fixtures/dependencies/package.json.diff +28 -0
  24. data/spec/fixtures/dependencies/package.json_patch_bumps_minor.diff +13 -0
  25. data/spec/fixtures/dependencies/package.json_patch_bumps_minor.json +112 -0
  26. data/spec/fixtures/dependencies/package.json_second_level_effect.diff +17 -0
  27. data/spec/fixtures/dependencies/package.json_second_level_effect.json +133 -0
  28. data/spec/fixtures/dependencies/yarn.lock +19609 -0
  29. data/spec/fixtures/dependencies/yarn.lock_patch_bumps_minor.lock +19614 -0
  30. data/spec/fixtures/dependencies/yarn.lock_second_level_effect.lock +20022 -0
  31. data/spec/fixtures/dependencies/yarn_list_second_level_effect.txt +1243 -0
  32. data/spec/fixtures/dependencies/yarn_list_second_level_effect.txt.diff +141 -0
  33. data/spec/fixtures/dependencies/yarn_minor_version.diff +33 -0
  34. data/spec/fixtures/dependencies/yarn_minor_version.txt +1151 -0
  35. data/spec/fixtures/dependencies/yarn_old.txt +1152 -0
  36. data/spec/fixtures/dependencies/yarn_patch_bumps_minor.diff +28 -0
  37. data/spec/fixtures/exception_inline_disabled_rule.diff +12 -0
  38. data/spec/fixtures/rubocop_exception.rb +3 -0
  39. data/spec/fixtures/yarn_deduplicate/list.a.txt +293 -0
  40. data/spec/fixtures/yarn_deduplicate/list.b.txt +295 -0
  41. data/spec/fixtures/yarn_deduplicate/list.diff +11 -0
  42. data/spec/fixtures/yarn_deduplicate/yarn.lock +20031 -0
  43. data/spec/fixtures_helper.rb +0 -1
  44. data/spec/spec_helper.rb +1 -1
  45. data/spec/wcc/commit_lint_spec.rb +6 -10
  46. data/spec/wcc/dependencies_spec.rb +129 -0
  47. data/spec/wcc/github_spec.rb +13 -7
  48. data/spec/wcc/jshint_spec.rb +1 -1
  49. data/spec/wcc/plugin_spec.rb +22 -17
  50. data/spec/wcc/reek_spec.rb +1 -1
  51. data/spec/wcc/rubocop_exceptions_spec.rb +34 -15
  52. data/spec/wcc/todos_spec.rb +10 -10
  53. data/spec/wcc/utils_spec.rb +2 -2
  54. data/spec/wcc/yarn_deduplicate_spec.rb +57 -0
  55. data/spec/wcc_spec.rb +1 -1
  56. metadata +71 -10
data/lib/wcc/todos.rb CHANGED
@@ -6,8 +6,8 @@ class Danger::DangerWCC < Danger::Plugin
6
6
  class Todos
7
7
  include Utils
8
8
 
9
- TODO_REGEX = /^\+.*\#.*TODO:?/i
10
- LINK_REGEX = /\#.*(https?\:\/\/\S+)/i
9
+ TODO_REGEX = /^\+.*\#.*TODO:?/i.freeze
10
+ LINK_REGEX = /\#.*(https?\:\/\/\S+)/i.freeze
11
11
 
12
12
  def initialize(plugin, options = {})
13
13
  @plugin = plugin
@@ -26,11 +26,11 @@ class Danger::DangerWCC < Danger::Plugin
26
26
  if result[:link]
27
27
  plugin.message "TODO added in #{result[:file_link]} "\
28
28
  "referencing [#{result[:link]}](#{result[:link]})",
29
- file: result[:file], line: result[:line]
29
+ file: result[:file], line: result[:line]
30
30
  else
31
31
  plugin.warn "TODO added in #{result[:file_link]} - "\
32
32
  'is there a card associated with that?',
33
- file: result[:file], line: result[:line]
33
+ file: result[:file], line: result[:line]
34
34
  end
35
35
  end
36
36
 
@@ -72,6 +72,7 @@ class Danger::DangerWCC < Danger::Plugin
72
72
  def max(a, b)
73
73
  return a if b.nil?
74
74
  return b if a.nil?
75
+
75
76
  a > b ? a : b
76
77
  end
77
78
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Danger::DangerWCC::Util
4
+ class YarnInfo
5
+ def yarn_lock
6
+ @yarn_lock ||= File.readlines(@options[:lockfile] || 'yarn.lock')
7
+ end
8
+
9
+ def package_json_dependencies
10
+ @package_json_dependencies ||=
11
+ JSON.parse(File.read('package.json'))['dependencies']&.keys || []
12
+ end
13
+
14
+ def package_json_changes
15
+ @package_json_changes ||= find_package_json_changes
16
+ end
17
+
18
+ def modified_yarn_dependencies
19
+ @modified_yarn_dependencies ||= find_modified_yarn_packages
20
+ end
21
+
22
+ attr_reader :plugin
23
+
24
+ def initialize(plugin, options = nil)
25
+ @plugin = plugin
26
+ @options = options || {}
27
+ end
28
+
29
+ def find_index_in_lockfile(package, version)
30
+ return 0 unless version
31
+
32
+ re = Regexp.new("^\"?#{Regexp.escape(package)}@", Regexp::IGNORECASE)
33
+ indexes =
34
+ yarn_lock.each_with_index
35
+ .select { |l, _i| re.match(l) }
36
+ .map { |pair| pair[1] }
37
+ idx =
38
+ indexes.find do |i|
39
+ yarn_lock[i + 1].include?("version \"#{version}\"")
40
+ end
41
+ (idx || -1) + 1
42
+ end
43
+
44
+ def parse_yarn_semver(line)
45
+ match = /(?<package>\S+)\@(?<version>\S+)/.match(line)
46
+ [match['package'], Gem::Version.new(match['version'])] if match
47
+ end
48
+
49
+ private
50
+
51
+ def find_package_json_changes
52
+ return [] unless file = plugin.find_file_in_diff('package.json')
53
+
54
+ adds = file.hunks.flat_map { |h| h.lines.select(&:addition?) }
55
+ adds.map { |l| /\"(?<package>\S+)\"\: \"\S+\"/.match(l.content) }
56
+ .compact
57
+ .map { |match| match['package'] }
58
+ end
59
+
60
+ def find_modified_yarn_packages # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
61
+ diff = plugin.run_and_diff(
62
+ 'NODE_ENV=production yarn list --depth 0 2>/dev/null'
63
+ )
64
+ diff = GitDiff.from_string(diff)
65
+
66
+ {}.tap do |modified_packages|
67
+ plugin.each_file_in_diff(diff) do |file, _diff|
68
+ file.hunks.each do |hunk|
69
+ deleted, added =
70
+ %i[deletion? addition?].map do |type|
71
+ Hash[hunk.lines.select { |l| l.public_send(type) }
72
+ .map { |l| parse_yarn_semver(l.content) }
73
+ .compact]
74
+ end
75
+ deleted.each do |(package, version)|
76
+ modified_packages[package] =
77
+ [version, added[package]]
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/wcc/utils.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'git_diff'
@@ -13,6 +12,7 @@ module Utils
13
12
 
14
13
  def logger
15
14
  return @logger if @logger
15
+
16
16
  @logger = Logger.new(STDERR)
17
17
  @logger.level = ENV['DANGER_LOG_LEVEL'] ||
18
18
  (plugin.verbose ? Logger::INFO : Logger::ERROR)
@@ -22,7 +22,7 @@ module Utils
22
22
  # All the diffs in the PR parsed into GitDiff objects
23
23
  def parsed_diffs
24
24
  @parsed_diffs ||=
25
- plugin.git.diff.map do |d|
25
+ plugin.git.diff&.map do |d|
26
26
  begin
27
27
  GitDiff.from_string(d.patch)
28
28
  rescue StandardError
@@ -32,6 +32,13 @@ module Utils
32
32
  end
33
33
  end
34
34
 
35
+ def find_file_in_diff(filename)
36
+ each_file_in_diff do |file, _diff|
37
+ return file if file.b_path == filename
38
+ end
39
+ nil
40
+ end
41
+
35
42
  # Finds lines in the overall diff matching the given regex, and
36
43
  # executes a block for each matched line.
37
44
  # The results of the yield block are returned as an array.
@@ -52,17 +59,22 @@ module Utils
52
59
 
53
60
  def each_file_in_diff(passed_diff = nil)
54
61
  diffs = passed_diff ? [passed_diff] : parsed_diffs
55
- diffs.flat_map do |diff|
62
+ diffs&.flat_map do |diff|
56
63
  diff.files.flat_map do |file|
57
64
  yield(file, diff)
58
65
  end
59
66
  end
60
67
  end
61
68
 
62
- def each_addition_in_diff(passed_diff = nil)
69
+ def each_addition_in_diff(passed_diff = nil, &block)
70
+ each_line_in_diff(passed_diff, type: :addition, &block)
71
+ end
72
+
73
+ def each_line_in_diff(passed_diff = nil, type: nil)
63
74
  each_file_in_diff(passed_diff) do |file, diff|
64
75
  file.hunks.flat_map do |hunk|
65
- lines = hunk.lines.select(&:addition?)
76
+ lines = hunk.lines
77
+ lines = lines.select { |l| l.public_send("#{type}?") } if type
66
78
  lines = lines.map { |l| yield(l, hunk, file, diff) } if block_given?
67
79
  lines
68
80
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'utils'
4
+
5
+ class Danger::DangerWCC < Danger::Plugin
6
+ class YarnDeduplicate
7
+ include Utils
8
+
9
+ DEFAULT_OPTIONS = {
10
+ lockfile: 'yarn.lock',
11
+ severity: :warn
12
+ }.freeze
13
+
14
+ def yarn_info
15
+ @yarn_info ||=
16
+ Danger::DangerWCC::Util::YarnInfo.new(self, @options)
17
+ end
18
+
19
+ def initialize(plugin, options = {})
20
+ @plugin = plugin
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ end
23
+
24
+ def perform
25
+ diff = run_yarn_deduplicate_diff
26
+
27
+ each_addition_in_diff(diff) do |line|
28
+ add_deduplicate_warning(line)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def run_yarn_deduplicate_diff
35
+ diff =
36
+ run_and_diff do
37
+ run('npx yarn-deduplicate -s fewer --list '\
38
+ "#{@options[:lockfile]}")
39
+ end
40
+ GitDiff.from_string(diff)
41
+ end
42
+
43
+ # rubocop:disable Layout/LineLength
44
+ DEDUPE_REGEXP = /^\+Package \"([^\"]+)\" wants (\S+) and could get (\S+), but got (\S+)$/i.freeze
45
+ # rubocop:enable Layout/LineLength
46
+
47
+ def add_deduplicate_warning(line) # rubocop:disable Metrics/MethodLength
48
+ warning = line.content.match(DEDUPE_REGEXP)
49
+ return unless warning
50
+
51
+ pkg, semver, wanted, got = warning.captures
52
+
53
+ idx = yarn_info.find_index_in_lockfile(
54
+ pkg, got
55
+ )
56
+ msg = <<~HEREDOC
57
+ You have an opportunity to deduplicate "#{pkg}".
58
+ It wants #{semver} and could unify with #{wanted}, but instead #{got}
59
+ was installed alongside it.
60
+
61
+ You can fix this by running :
62
+ `npx yarn-deduplicate -s fewer --packages "#{pkg}"`
63
+ HEREDOC
64
+ plugin.public_send(@options[:severity],
65
+ msg,
66
+ file: @options[:lockfile],
67
+ line: idx)
68
+ end
69
+ end
70
+ end
71
+
72
+ require_relative './util/yarn_info'
@@ -0,0 +1,112 @@
1
+ {
2
+ "name": "paper-signs",
3
+ "private": true,
4
+ "workspaces": [
5
+ ".",
6
+ "packages/*"
7
+ ],
8
+ "scripts": {
9
+ "fix-css": "stylelint app/**/*.scss --syntax scss --fix",
10
+ "fix-js": "tslint --project tsconfig.json app/assets/javascripts/**/*.ts?\\(x\\) --fix",
11
+ "fix": "yarn fix-js && yarn fix-css",
12
+ "check-types": "tsc --noemit",
13
+ "lint": "yarn lint-js && yarn lint-css",
14
+ "lint-css": "stylelint app/**/*.scss --syntax scss",
15
+ "lint-js": "tslint --project tsconfig.json app/assets/javascripts/**/*.ts?\\(x\\)",
16
+ "analyze": "RAILS_ENV=production NODE_ENV=production bin/webpack --profile --json > tmp/stats.json && webpack-bundle-analyzer tmp/stats.json public/packs --exclude server_rendering -m static",
17
+ "test": "jest && NODE_ENV=test karma start --",
18
+ "test-css": "mocha app/assets/stylesheets/true.js",
19
+ "test-watch": "NODE_ENV=test karma start --auto-watch --no-single-run",
20
+ "prepare": "contentful-ts-generator --download=false && for d in packages/*/; do (cd $d; yarn prepare) || exit -1; done"
21
+ },
22
+ "engines": {},
23
+ "dependencies": {
24
+ "@babel/core": "^7.8.3",
25
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
26
+ "@babel/preset-env": "^7.8.3",
27
+ "@babel/preset-react": "^7.8.3",
28
+ "@babel/preset-typescript": "^7.8.3",
29
+ "@rails/webpacker": "^4.0.2",
30
+ "@types/algoliasearch": "^3.30.1",
31
+ "@types/algoliasearch-helper": "^2.26.1",
32
+ "@types/bootstrap": "^4.3.1",
33
+ "@types/bugsnag-js": "^3.1.0",
34
+ "@types/chai": "^4.1.7",
35
+ "@types/chai-jquery": "^1.1.38",
36
+ "@types/enzyme": "^3.1.15",
37
+ "@types/enzyme-adapter-react-16": "^1.0.3",
38
+ "@types/fontfaceobserver": "^0.0.6",
39
+ "@types/i18n-js": "^3.0.1",
40
+ "@types/lodash": "^4.14.134",
41
+ "@types/mocha": "^5.2.5",
42
+ "@types/qs": "^6.5.3",
43
+ "@types/react": "^16.9.34",
44
+ "@types/react-dom": "^16.0.9",
45
+ "@types/react-infinite-scroller": "^1.2.1",
46
+ "@types/react-instantsearch": "^5.2.1",
47
+ "@types/sinon": "^7.0.3",
48
+ "@types/webpack-env": "^1.13.9",
49
+ "@watermarkchurch/contentful-migration": "^1.0.9",
50
+ "@watermarkchurch/react-instantsearch-components": "*",
51
+ "async-toolbox": "^0.6.6",
52
+ "babel-preset-react": "^6.24.1",
53
+ "contentful-export": "^7.4.0",
54
+ "contentful-shell": "^0.2.7",
55
+ "contentful-ts-generator": "^0.2.4",
56
+ "core-js": "3",
57
+ "date-fns": "^1.30.1",
58
+ "enzyme": "^3.7.0",
59
+ "enzyme-adapter-react-16": "^1.7.0",
60
+ "fontfaceobserver": "^2.1.0",
61
+ "html-react-parser": "^0.9.1",
62
+ "i18n-js": "^3.5.1",
63
+ "identity-obj-proxy": "^3.0.0",
64
+ "inflection": "^1.12.0",
65
+ "postcss-cssnext": "^3.1.0",
66
+ "prop-types": "^15.6.2",
67
+ "qs": "^6.7.0",
68
+ "react": "^16.12.0",
69
+ "react-calendar": "^2.19.0",
70
+ "react-dom": "^16.12.0",
71
+ "react-infinite-scroller": "^1.2.2",
72
+ "react-instantsearch": "^5.3.2",
73
+ "react-svg-loader": "^3.0.3",
74
+ "react_ujs": "^2.4.4",
75
+ "sinon": "^7.2.2",
76
+ "typescript": "^3.3.3"
77
+ },
78
+ "devDependencies": {
79
+ "@percy/agent": "^0.28.0",
80
+ "@types/jest": "^25.2.1",
81
+ "@watermarkchurch/contentful-check": "*",
82
+ "@watermarkchurch/load-tester": "*",
83
+ "babel-jest": "^25.5.0",
84
+ "chai": "^4.2.0",
85
+ "chai-jquery": "^2.0.0",
86
+ "graphql-schema-diff": "^0.6.3",
87
+ "hard-source-webpack-plugin": "^0.13.1",
88
+ "jest": "^25.5.0",
89
+ "karma": "^3.1.1",
90
+ "karma-chai": "^0.1.0",
91
+ "karma-chai-jquery": "^1.0.0",
92
+ "karma-chrome-launcher": "^2.2.0",
93
+ "karma-jquery": "^0.2.3",
94
+ "karma-junit-reporter": "^1.2.0",
95
+ "karma-mocha": "^1.3.0",
96
+ "karma-mocha-reporter": "^2.2.5",
97
+ "karma-sourcemap-loader": "^0.3.7",
98
+ "karma-webpack": "^3.0.5",
99
+ "lerna": "^3.13.1",
100
+ "mocha": "^5.2.0",
101
+ "react-test-renderer": "^16.12.0",
102
+ "sass-true": "^4.0.0",
103
+ "stylelint": "^9.6.0",
104
+ "stylelint-config-sass-guidelines": "^5.2.0",
105
+ "stylelint-scss": "^3.3.2",
106
+ "ts-node": "^7.0.1",
107
+ "tslint": "^5.11.0",
108
+ "tslint-eslint-rules": "^5.4.0",
109
+ "webpack-bundle-analyzer": "^3.0.3",
110
+ "webpack-dev-server": "^3.3.1"
111
+ }
112
+ }
@@ -0,0 +1,28 @@
1
+ diff --git a/package.json b/package.json
2
+ index 74d7ad8a..ea999d34 100644
3
+ --- a/package.json
4
+ +++ b/package.json
5
+ @@ -41,7 +41,6 @@
6
+ "@types/mocha": "^5.2.5",
7
+ "@types/qs": "^6.5.3",
8
+ "@types/react": "^16.9.34",
9
+ - "@types/react-autosuggest": "^9.3.6",
10
+ "@types/react-dom": "^16.0.9",
11
+ "@types/react-infinite-scroller": "^1.2.1",
12
+ "@types/react-instantsearch": "^5.2.1",
13
+ @@ -67,7 +66,6 @@
14
+ "prop-types": "^15.6.2",
15
+ "qs": "^6.7.0",
16
+ "react": "^16.12.0",
17
+ - "react-autosuggest": "^9.4.3",
18
+ "react-calendar": "^2.19.0",
19
+ "react-dom": "^16.12.0",
20
+ "react-infinite-scroller": "^1.2.2",
21
+ @@ -78,6 +76,7 @@
22
+ "typescript": "^3.3.3"
23
+ },
24
+ "devDependencies": {
25
+ + "@percy/agent": "^0.28.0",
26
+ "@types/jest": "^25.2.1",
27
+ "@watermarkchurch/contentful-check": "*",
28
+ "@watermarkchurch/load-tester": "*",
@@ -0,0 +1,13 @@
1
+ diff --git a/package.json b/package.json
2
+ index ea999d3..efa8440 100644
3
+ --- a/package.json
4
+ +++ b/package.json
5
+ @@ -69,7 +69,7 @@
6
+ "react-calendar": "^2.19.0",
7
+ "react-dom": "^16.12.0",
8
+ "react-infinite-scroller": "^1.2.2",
9
+ - "react-instantsearch": "^5.3.2",
10
+ + "react-instantsearch": "^5.3.3",
11
+ "react-svg-loader": "^3.0.3",
12
+ "react_ujs": "^2.4.4",
13
+ "sinon": "^7.2.2",
@@ -0,0 +1,112 @@
1
+ {
2
+ "name": "paper-signs",
3
+ "private": true,
4
+ "workspaces": [
5
+ ".",
6
+ "packages/*"
7
+ ],
8
+ "scripts": {
9
+ "fix-css": "stylelint app/**/*.scss --syntax scss --fix",
10
+ "fix-js": "tslint --project tsconfig.json app/assets/javascripts/**/*.ts?\\(x\\) --fix",
11
+ "fix": "yarn fix-js && yarn fix-css",
12
+ "check-types": "tsc --noemit",
13
+ "lint": "yarn lint-js && yarn lint-css",
14
+ "lint-css": "stylelint app/**/*.scss --syntax scss",
15
+ "lint-js": "tslint --project tsconfig.json app/assets/javascripts/**/*.ts?\\(x\\)",
16
+ "analyze": "RAILS_ENV=production NODE_ENV=production bin/webpack --profile --json > tmp/stats.json && webpack-bundle-analyzer tmp/stats.json public/packs --exclude server_rendering -m static",
17
+ "test": "jest && NODE_ENV=test karma start --",
18
+ "test-css": "mocha app/assets/stylesheets/true.js",
19
+ "test-watch": "NODE_ENV=test karma start --auto-watch --no-single-run",
20
+ "prepare": "contentful-ts-generator --download=false && for d in packages/*/; do (cd $d; yarn prepare) || exit -1; done"
21
+ },
22
+ "engines": {},
23
+ "dependencies": {
24
+ "@babel/core": "^7.8.3",
25
+ "@babel/plugin-proposal-class-properties": "^7.8.3",
26
+ "@babel/preset-env": "^7.8.3",
27
+ "@babel/preset-react": "^7.8.3",
28
+ "@babel/preset-typescript": "^7.8.3",
29
+ "@rails/webpacker": "^4.0.2",
30
+ "@types/algoliasearch": "^3.30.1",
31
+ "@types/algoliasearch-helper": "^2.26.1",
32
+ "@types/bootstrap": "^4.3.1",
33
+ "@types/bugsnag-js": "^3.1.0",
34
+ "@types/chai": "^4.1.7",
35
+ "@types/chai-jquery": "^1.1.38",
36
+ "@types/enzyme": "^3.1.15",
37
+ "@types/enzyme-adapter-react-16": "^1.0.3",
38
+ "@types/fontfaceobserver": "^0.0.6",
39
+ "@types/i18n-js": "^3.0.1",
40
+ "@types/lodash": "^4.14.134",
41
+ "@types/mocha": "^5.2.5",
42
+ "@types/qs": "^6.5.3",
43
+ "@types/react": "^16.9.34",
44
+ "@types/react-dom": "^16.0.9",
45
+ "@types/react-infinite-scroller": "^1.2.1",
46
+ "@types/react-instantsearch": "^5.2.1",
47
+ "@types/sinon": "^7.0.3",
48
+ "@types/webpack-env": "^1.13.9",
49
+ "@watermarkchurch/contentful-migration": "^1.0.9",
50
+ "@watermarkchurch/react-instantsearch-components": "*",
51
+ "async-toolbox": "^0.6.6",
52
+ "babel-preset-react": "^6.24.1",
53
+ "contentful-export": "^7.4.0",
54
+ "contentful-shell": "^0.2.7",
55
+ "contentful-ts-generator": "^0.2.4",
56
+ "core-js": "3",
57
+ "date-fns": "^1.30.1",
58
+ "enzyme": "^3.7.0",
59
+ "enzyme-adapter-react-16": "^1.7.0",
60
+ "fontfaceobserver": "^2.1.0",
61
+ "html-react-parser": "^0.9.1",
62
+ "i18n-js": "^3.5.1",
63
+ "identity-obj-proxy": "^3.0.0",
64
+ "inflection": "^1.12.0",
65
+ "postcss-cssnext": "^3.1.0",
66
+ "prop-types": "^15.6.2",
67
+ "qs": "^6.7.0",
68
+ "react": "^16.12.0",
69
+ "react-calendar": "^2.19.0",
70
+ "react-dom": "^16.12.0",
71
+ "react-infinite-scroller": "^1.2.2",
72
+ "react-instantsearch": "^5.3.3",
73
+ "react-svg-loader": "^3.0.3",
74
+ "react_ujs": "^2.4.4",
75
+ "sinon": "^7.2.2",
76
+ "typescript": "^3.3.3"
77
+ },
78
+ "devDependencies": {
79
+ "@percy/agent": "^0.28.0",
80
+ "@types/jest": "^25.2.1",
81
+ "@watermarkchurch/contentful-check": "*",
82
+ "@watermarkchurch/load-tester": "*",
83
+ "babel-jest": "^25.5.0",
84
+ "chai": "^4.2.0",
85
+ "chai-jquery": "^2.0.0",
86
+ "graphql-schema-diff": "^0.6.3",
87
+ "hard-source-webpack-plugin": "^0.13.1",
88
+ "jest": "^25.5.0",
89
+ "karma": "^3.1.1",
90
+ "karma-chai": "^0.1.0",
91
+ "karma-chai-jquery": "^1.0.0",
92
+ "karma-chrome-launcher": "^2.2.0",
93
+ "karma-jquery": "^0.2.3",
94
+ "karma-junit-reporter": "^1.2.0",
95
+ "karma-mocha": "^1.3.0",
96
+ "karma-mocha-reporter": "^2.2.5",
97
+ "karma-sourcemap-loader": "^0.3.7",
98
+ "karma-webpack": "^3.0.5",
99
+ "lerna": "^3.13.1",
100
+ "mocha": "^5.2.0",
101
+ "react-test-renderer": "^16.12.0",
102
+ "sass-true": "^4.0.0",
103
+ "stylelint": "^9.6.0",
104
+ "stylelint-config-sass-guidelines": "^5.2.0",
105
+ "stylelint-scss": "^3.3.2",
106
+ "ts-node": "^7.0.1",
107
+ "tslint": "^5.11.0",
108
+ "tslint-eslint-rules": "^5.4.0",
109
+ "webpack-bundle-analyzer": "^3.0.3",
110
+ "webpack-dev-server": "^3.3.1"
111
+ }
112
+ }