squared 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,29 +4,38 @@ module Squared
4
4
  module Workspace
5
5
  module Project
6
6
  class Node < Git
7
+ include Common::Prompt
8
+
7
9
  class << self
8
10
  def populate(*); end
9
11
 
10
12
  def tasks
11
- nil
13
+ %i[outdated].freeze
14
+ end
15
+
16
+ def batchargs
17
+ [ref, { refresh: %i[build copy] }]
18
+ end
19
+
20
+ def aliasargs
21
+ [ref, { refresh: :build }]
12
22
  end
13
23
 
14
24
  def prod?
15
25
  ENV['NODE_ENV'] == 'production'
16
26
  end
17
27
 
18
- def is_a?(val)
19
- if (val = as_path(val))
20
- val.join('package.json').exist?
21
- else
22
- super
23
- end
28
+ def config?(val)
29
+ return false unless (val = as_path(val))
30
+
31
+ val.join('package.json').exist?
24
32
  end
25
33
  end
26
34
 
27
35
  @@tasks[ref] = {
28
- install: %i[force frozen dedupe],
29
- outdated: %i[major minor patch],
36
+ install: %i[force frozen dedupe].freeze,
37
+ outdated: %i[major minor patch].freeze,
38
+ bump: %i[major minor patch].freeze,
30
39
  run: nil
31
40
  }.freeze
32
41
 
@@ -58,11 +67,55 @@ module Squared
58
67
  if flags.nil?
59
68
  case action
60
69
  when :run
61
- desc format_desc(action, nil, 'command+')
70
+ desc format_desc(action, nil, 'command+|^index|#,pattern*')
62
71
  task action, [:command] do |_, args|
63
- cmd = args.to_a
64
- guard_params(action, 'command', args: cmd)
65
- cmd.each { |val| run_s compose(val) }
72
+ if args.command == '#'
73
+ list = read_scripts
74
+ grep = args.extras.map { |val| Regexp.new(val) }
75
+ lines = []
76
+ if (pad = list.size) > 0
77
+ pad = pad.to_s.size
78
+ list.each_with_index do |val, i|
79
+ next unless grep.empty? || grep.any? { |pat| pat.match?(val[0]) }
80
+
81
+ lines << "#{(i + 1).to_s.rjust(pad)}. #{val[0]}"
82
+ end
83
+ end
84
+ if lines.empty?
85
+ lines = ['No scripts were found:', '']
86
+ unless args.extras.empty?
87
+ i = 0
88
+ lines += args.extras.to_a.map { |s| "#{i += 1}. #{s}" }
89
+ lines << ''
90
+ end
91
+ lines << package.to_s
92
+ pat = /^(#{Regexp.escape(lines.last)})(.*)$/
93
+ else
94
+ pat = /^(\s*\d+\.)(.+)$/
95
+ end
96
+ emphasize(lines, title: task_join(name, 'run[^N]'), border: borderstyle, sub: [
97
+ headerstyle,
98
+ { pat: pat, styles: theme[:active] }
99
+ ])
100
+ else
101
+ cmd = args.to_a
102
+ guard_params(action, 'command', args: cmd)
103
+ list = nil
104
+ cmd.each do |val|
105
+ if (data = /\A\^(\d+)\z/.match(val))
106
+ list ||= read_scripts
107
+ n = data[1].to_i
108
+ if (item = list[n - 1])
109
+ val = item.first
110
+ elsif exception
111
+ raise_error("requested index #{n}", hint: "total #{list.size}")
112
+ else
113
+ next log.warn "run script #{n} of #{list.size} (out of range)"
114
+ end
115
+ end
116
+ run compose(val, script: true)
117
+ end
118
+ end
66
119
  end
67
120
  end
68
121
  else
@@ -75,10 +128,15 @@ module Squared
75
128
  depend(flag)
76
129
  end
77
130
  when :outdated
78
- desc format_desc(action, flag, %w[prune interactive dry-run], arg: 'opts?')
131
+ desc format_desc(action, flag, %w[prune interactive dry-run].freeze, arg: 'opts?')
79
132
  task flag, [:opts] do |_, args|
80
133
  outdated(flag, opts: args.to_a)
81
134
  end
135
+ else
136
+ desc format_desc(action, flag)
137
+ task flag do
138
+ __send__(action, flag)
139
+ end
82
140
  end
83
141
  end
84
142
  end
@@ -87,17 +145,17 @@ module Squared
87
145
  end
88
146
  end
89
147
 
90
- def copy(from: 'build', glob: '**/*', subdir: 'node_modules', into: nil, also: nil, override: false)
148
+ def copy(from: 'build', glob: '**/*', into: 'node_modules', scope: nil, also: nil, override: false)
91
149
  if @copy && !override
92
150
  return super if runnable?(@copy)
93
151
 
94
152
  from = @copy[:from] if @copy.key?(:from)
95
153
  glob = @copy[:glob] if @copy.key?(:glob)
96
- subdir = @copy[:subdir] if @copy.key?(:subdir)
97
154
  into = @copy[:into] if @copy.key?(:into)
155
+ scope = @copy[:scope] if @copy.key?(:scope)
98
156
  also = @copy[:also] if @copy.key?(:also)
99
157
  end
100
- items = [path == workspace.home ? nil : workspace.home]
158
+ items = [path != workspace.home && workspace.home? ? workspace.home : nil]
101
159
  items += as_a(also) if also
102
160
  items.each_with_index do |dir, i|
103
161
  if i == 0
@@ -113,7 +171,7 @@ module Squared
113
171
  when ::Hash
114
172
  glob = '**/*'
115
173
  dest = nil
116
- into = nil
174
+ scope = nil
117
175
  dir.each do |key, val|
118
176
  case key.to_sym
119
177
  when :target
@@ -122,8 +180,8 @@ module Squared
122
180
  from = val
123
181
  when :glob
124
182
  glob = val
125
- when :subdir
126
- subdir = val
183
+ when :scope
184
+ scope = val
127
185
  when :into
128
186
  into = val
129
187
  end
@@ -131,18 +189,17 @@ module Squared
131
189
  when Project::Base
132
190
  dest = dir.path
133
191
  end
134
- next unless into
135
192
  end
136
193
  next unless dest&.directory?
137
194
 
138
195
  from = base_path(from)
139
- dest = dest.join(subdir, into || project)
140
- log.warn "cp #{from.join(glob)} #{dest}"
196
+ dest = dest.join(into, scope || project)
197
+ (glob = as_a(glob)).each { |val| log.info "cp #{from.join(val)} #{dest}" }
141
198
  copy_d(from, dest, glob: glob, verbose: verbose)
142
199
  end
143
200
  end
144
201
 
145
- def depend(flag = nil)
202
+ def depend(flag = nil, sync: invoked_sync?('depend', flag))
146
203
  if @depend && !flag
147
204
  super
148
205
  elsif outdated?
@@ -165,7 +222,7 @@ module Squared
165
222
  '--frozen-lockfile'
166
223
  end
167
224
  cmd << '--production' if flag && prod?
168
- cmd << '--ignore-engines' unless env('YARN_IGNORE_ENGINES', equals: '0')
225
+ cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
169
226
  end
170
227
  elsif pnpm?
171
228
  cmd = session 'pnpm'
@@ -179,11 +236,11 @@ module Squared
179
236
  end
180
237
  end
181
238
  cmd << '--prod' if flag && prod?
182
- if (val = env('PNPM_PUBLIC_HOIST_PATTERN'))
239
+ if (val = option('public-hoist-pattern', ignore: false))
183
240
  split_escape(val).each { |opt| cmd << "--public-hoist-pattern=#{shell_escape(opt, quote: true)}" }
184
241
  end
185
242
  cmd << '--ignore-workspace' if env('NODE_WORKSPACES', equals: '0')
186
- append_nocolor
243
+ append_nocolor option('no-color')
187
244
  else
188
245
  cmd = session 'npm'
189
246
  if flag == :dedupe
@@ -197,17 +254,23 @@ module Squared
197
254
  end
198
255
  cmd << '--omit=dev' if flag && prod?
199
256
  cmd << '--workspaces=false' if env('NODE_WORKSPACES', equals: '0')
200
- cmd << '--package-lock=false' if env('NPM_PACKAGE_LOCK', equals: '0')
201
- append_nocolor
257
+ cmd << '--package-lock=false' if option('package-lock', equals: '0')
258
+ append_nocolor option('no-color')
202
259
  end
203
260
  append_loglevel
204
- run(sync: invoked_sync?('depend', flag))
261
+ run(sync: sync)
205
262
  end
206
263
  end
207
264
 
208
265
  def outdated(rev = nil, opts: [])
209
- dryrun = opts.include?('dry-run') || !env('NODE_DRY_RUN').nil?
210
- cmd = pnpm? && read_packagemanager(ver: '7.15') ? 'pnpm outdated' : 'npm outdated'
266
+ dryrun = opts.include?('dry-run')
267
+ if pnpm? && read_packagemanager(version: '7.15')
268
+ cmd = 'pnpm outdated'
269
+ dryrun ||= !option('dry-run', prefix: 'pnpm').nil?
270
+ else
271
+ cmd = 'npm outdated'
272
+ dryrun ||= !option('dry-run', prefix: 'npm').nil?
273
+ end
211
274
  log.info cmd
212
275
  banner = format_banner("#{cmd}#{dryrun ? ' --dry-run' : ''}", multiple: true)
213
276
  if invoked_sync?('outdated', rev)
@@ -226,7 +289,7 @@ module Squared
226
289
  unless data.empty?
227
290
  JSON.parse(data).each_pair do |key, val|
228
291
  val = val.find { |obj| obj['dependent'] == json['name'] } if val.is_a?(::Array)
229
- next unless val && (file = dep1[key] || dep2[key])
292
+ next unless val && (file = dep1[key] || dep2[key]) && file != '*'
230
293
 
231
294
  latest = val['latest']
232
295
  ch = file[0]
@@ -238,11 +301,11 @@ module Squared
238
301
  avail << [key, file, latest, true]
239
302
  next
240
303
  end
241
- want = rev == :major && latest.match(SEM_VER) && !Regexp.last_match(6) ? latest : val['wanted']
304
+ want = rev == :major && (ver = latest.match(SEM_VER)) && !ver[6] ? latest : val['wanted']
242
305
  next unless (val['current'] != want || file != want) && (want.match?(SEM_VER) || !file.match?(SEM_VER))
243
306
 
244
- f = semver(file.scan(SEM_VER)).first
245
- w = semver(want.scan(SEM_VER)).first
307
+ f = semver(semscan(file))
308
+ w = semver(semscan(want))
246
309
  a = f[0]
247
310
  b = f[2]
248
311
  c = w[0]
@@ -294,7 +357,7 @@ module Squared
294
357
  col2 = size_col.(found, 1) + 4
295
358
  found.each_with_index do |item, i|
296
359
  a, b, c, d, e = item
297
- if inter && (rev != :major || e || semmajor(item[5], item[6])) && !confirm_outdated(a, c, d)
360
+ if inter && (rev != :major || e || semmajor(item[5], item[6])) && !confirm_outdated(a, c, d, e)
298
361
  cur = -1
299
362
  else
300
363
  cur = modified
@@ -354,12 +417,14 @@ module Squared
354
417
  end
355
418
  end
356
419
 
357
- def compose(opts)
420
+ def compose(opts, flags = nil, script: false)
421
+ return unless opts && script
422
+
358
423
  ret = session (if yarn?
359
424
  'yarn'
360
425
  else
361
426
  pnpm? ? 'pnpm' : 'npm'
362
- end), 'run'
427
+ end), 'run', flags
363
428
  append_loglevel
364
429
  case opts
365
430
  when ::Enumerable
@@ -372,6 +437,57 @@ module Squared
372
437
  ret
373
438
  end
374
439
 
440
+ def bump(flag)
441
+ return unless (ver = version)
442
+
443
+ seg = semscan(ver)
444
+ case flag
445
+ when :major
446
+ if seg[0] != '0' || seg[2].nil?
447
+ seg[0] = seg[0].succ
448
+ else
449
+ seg[2] = seg[2].succ
450
+ end
451
+ when :minor
452
+ if seg[0] == '0'
453
+ seg[4] &&= seg[4].succ
454
+ else
455
+ seg[2] = seg[2].succ
456
+ end
457
+ when :patch
458
+ seg[4] &&= seg[4].succ
459
+ end
460
+ unless (out = seg.join) == ver
461
+ begin
462
+ doc = package.read
463
+ if doc.sub!(/"version"\s*:\s*"#{ver}"/, "\"version\": \"#{out}\"")
464
+ package.write(doc)
465
+ log.info "bump version #{ver} to #{out} (#{flag})"
466
+ if verbose
467
+ major = flag == :major
468
+ emphasize("version: #{out}", title: name, border: borderstyle, sub: [
469
+ headerstyle,
470
+ { pat: /^(version:)( )(\S+)(.*)$/, styles: color(major ? :green : :yellow), index: 3 },
471
+ { pat: /^(version:)(.*)$/, styles: theme[major ? :major : :active] }
472
+ ])
473
+ elsif stdin?
474
+ puts out
475
+ end
476
+ else
477
+ raise_error('not found', hint: 'version')
478
+ end
479
+ rescue StandardError => e
480
+ log.debug e
481
+ raise
482
+ end
483
+ end
484
+ end
485
+
486
+ def version
487
+ read_packagemanager
488
+ @pm[:version]
489
+ end
490
+
375
491
  def install_type(prog = nil)
376
492
  prog ||= yarn? ? :yarn : :pnpm
377
493
  key = :"#{prog}?"
@@ -379,6 +495,10 @@ module Squared
379
495
  @pm[prog] || 0
380
496
  end
381
497
 
498
+ def depend?
499
+ @depend != false && (!@depend.nil? || outdated?)
500
+ end
501
+
382
502
  def copy?
383
503
  super || @copy.is_a?(::Hash)
384
504
  end
@@ -388,8 +508,8 @@ module Squared
388
508
  end
389
509
 
390
510
  def yarn?
391
- (@pm[:yarn] ||= if base_path('yarn.lock').exist?
392
- if (rc = base_path('.yarnrc.yml')).exist?
511
+ (@pm[:yarn] ||= if base_path('yarn.lock', ascend: find_package).exist?
512
+ if (rc = base_path('.yarnrc.yml', ascend: find_package)).exist?
393
513
  begin
394
514
  require 'yaml'
395
515
  doc = YAML.load_file(rc)
@@ -408,10 +528,10 @@ module Squared
408
528
  end
409
529
 
410
530
  def pnpm?
411
- (@pm[:pnpm] ||= if base_path('pnpm-lock.yaml').exist?
531
+ (@pm[:pnpm] ||= if base_path('pnpm-lock.yaml', ascend: find_package).exist?
412
532
  begin
413
533
  require 'yaml'
414
- doc = YAML.load_file(base_path('node_modules/.modules.yaml'))
534
+ doc = YAML.load_file(base_path('node_modules/.modules.yaml', ascend: find_package))
415
535
  @pm[:_] = doc['packageManager']
416
536
  case doc['nodeLinker']
417
537
  when 'hoisted'
@@ -429,6 +549,15 @@ module Squared
429
549
  end) > 0
430
550
  end
431
551
 
552
+ def workspaces?
553
+ if pnpm?
554
+ base_path('pnpm-workspace.yaml').exist?
555
+ else
556
+ read_packagemanager
557
+ @pm[:workspaces].is_a?(::Array)
558
+ end
559
+ end
560
+
432
561
  def dev?
433
562
  !Node.prod? && super
434
563
  end
@@ -439,6 +568,36 @@ module Squared
439
568
 
440
569
  private
441
570
 
571
+ def read_packagemanager(version: nil)
572
+ if @pm[:_].nil?
573
+ doc = JSON.parse(package.read)
574
+ @pm[:_] = (val = doc['packageManager']) ? val[0..(val.index('+') || 0) - 1] : false
575
+ @pm[:scripts] = doc['scripts']
576
+ @pm[:version] = doc['version']
577
+ @pm[:workspaces] = doc['workspaces']
578
+ end
579
+ rescue StandardError => e
580
+ log.debug e if package.exist?
581
+ @pm[:_] = false
582
+ nil
583
+ else
584
+ return if !@pm[:_] || (version && @pm[:_][@pm[:_].index('@') + 1..-1] < version)
585
+
586
+ @pm[:_]
587
+ end
588
+
589
+ def read_install
590
+ return unless (ret = env('NODE_INSTALL'))
591
+
592
+ @pm[:_] ||= ret if ret.include?('@')
593
+ ret
594
+ end
595
+
596
+ def read_scripts
597
+ read_packagemanager
598
+ @pm[:scripts].is_a?(Hash) ? @pm[:scripts].to_a : []
599
+ end
600
+
442
601
  def append_loglevel
443
602
  level = env('NODE_LOGLEVEL')
444
603
  silent = !verbose || level == 'silent'
@@ -471,43 +630,31 @@ module Squared
471
630
  end
472
631
  end
473
632
 
474
- def confirm_outdated(pkg, ver, rev)
475
- rev = case rev
476
- when 1
477
- 'MAJOR'
478
- when 3
479
- 'MINOR'
480
- else
481
- 'PATCH'
482
- end
483
- a = sub_style(rev, styles: theme[:header])
633
+ def confirm_outdated(pkg, ver, rev, lock)
634
+ a = sub_style(case rev
635
+ when 1
636
+ 'MAJOR'
637
+ when 3
638
+ 'MINOR'
639
+ else
640
+ 'PATCH'
641
+ end, styles: theme[:header])
484
642
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
485
- c, d = rev == 'MAJOR' ? ['y/N', 'N'] : ['Y/n', 'Y']
486
- confirm("Upgrade to #{a}? #{b} [#{c}] ", d, timeout: 60)
643
+ c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
644
+ e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
645
+ confirm("Upgrade to #{a}? #{b}#{e} [#{c}] ", d, timeout: 60)
487
646
  end
488
647
 
489
- def read_packagemanager(ver: nil)
490
- if @pm[:_].nil?
491
- doc = JSON.parse(package.read)
492
- @pm[:_] = (val = doc['packageManager']) ? val[0..(val.index('+') || 0) - 1] : false
493
- end
494
- rescue StandardError => e
495
- log.warn e if package.exist?
496
- @pm[:_] = false
497
- nil
498
- else
499
- return unless @pm[:_]
500
-
501
- ver ? @pm[:_][@pm[:_].index('@') + 1..-1] >= ver : @pm[:_]
648
+ def find_package
649
+ 'package.json' if parent&.has?('outdated', Node.ref)
502
650
  end
503
651
 
504
- def read_install
505
- return unless (ret = env('NODE_INSTALL'))
506
-
507
- @pm[:_] ||= ret if ret.include?('@')
508
- ret
652
+ def headerstyle
653
+ { pat: /^(\S+)(\s+)$/, styles: theme[:header] }
509
654
  end
510
655
  end
656
+
657
+ Application.implement Node
511
658
  end
512
659
  end
513
660
  end
@@ -12,21 +12,21 @@ module Squared
12
12
 
13
13
  class << self
14
14
  def populate(*); end
15
+ def batchargs(*); end
16
+ def aliasargs(*); end
15
17
 
16
18
  def tasks
17
- nil
19
+ %i[outdated].freeze
18
20
  end
19
21
 
20
22
  def venv?
21
23
  Dir.exist?(ENV.fetch('VIRTUAL_ENV', ''))
22
24
  end
23
25
 
24
- def is_a?(val)
25
- if (val = as_path(val))
26
- REQUIREMENTS.any? { |file| val.join(file).exist? }
27
- else
28
- super
29
- end
26
+ def config?(val)
27
+ return false unless (val = as_path(val))
28
+
29
+ REQUIREMENTS.any? { |file| val.join(file).exist? }
30
30
  end
31
31
  end
32
32
 
@@ -46,7 +46,7 @@ module Squared
46
46
  end
47
47
 
48
48
  @@tasks[ref] = {
49
- install: %i[user target upgrade force]
49
+ install: %i[user target upgrade force].freeze
50
50
  }.freeze
51
51
 
52
52
  def ref
@@ -74,7 +74,8 @@ module Squared
74
74
  else
75
75
  OPT_USER
76
76
  end
77
- desc format_desc(action, flag, list + OPT_GENERAL, req: req)
77
+ list += OPT_GENERAL
78
+ desc format_desc(action, flag, list, req: req)
78
79
  if flag == :target
79
80
  task flag, [:dir, :opts] do |_, args|
80
81
  guard_params(action, flag, args: args, key: :dir)
@@ -92,11 +93,10 @@ module Squared
92
93
  end
93
94
  end
94
95
 
95
- def depend(flag = nil, dir: nil, opts: [])
96
+ def depend(flag = nil, dir: nil, opts: [], sync: invoked_sync?('depend', flag))
96
97
  if @depend && !flag
97
98
  super
98
99
  elsif outdated?
99
- sync = invoked_sync?('depend', flag)
100
100
  case (type = install_type)
101
101
  when 1, 2
102
102
  cmd = pip_session 'install'
@@ -148,6 +148,10 @@ module Squared
148
148
  end
149
149
  end
150
150
 
151
+ def depend?
152
+ @depend != false && (!@depend.nil? || outdated?)
153
+ end
154
+
151
155
  def outdated?
152
156
  install_type > 0
153
157
  end
@@ -169,21 +173,23 @@ module Squared
169
173
  (v ? "-#{v[0]}" : "--#{opt}")
170
174
  end
171
175
  end
172
- @session << '--user' if env('PIP_USER')
173
- @session << '--no-input' if env('PIP_NO_INPUT')
174
- if (val = env('PIP_PROXY'))
176
+ @session << '--user' if option('user')
177
+ @session << '--no-input' if option('no-input')
178
+ if (val = option('proxy', ignore: false))
175
179
  @session << "--proxy=#{shell_escape(val, quote: true)}"
176
180
  end
177
- if (val = env('PIP_LOG'))
181
+ if (val = option('log', ignore: false))
178
182
  @session << "--log=#{shell_escape(base_path(val).to_s, quote: true)}"
179
183
  end
180
- append_nocolor
184
+ append_nocolor option('no-color')
181
185
  end
182
186
 
183
187
  def append_eager(opts)
184
188
  @session << '--upgrade-strategy=eager' if opts.include?('eager')
185
189
  end
186
190
  end
191
+
192
+ Application.implement Python
187
193
  end
188
194
  end
189
195
  end