squared 0.2.11 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,11 +4,57 @@ module Squared
4
4
  module Workspace
5
5
  module Project
6
6
  class Node < Git
7
+ OPT_NPM = {
8
+ common: %w[dry-run include-workspace-root workspaces w|workspace=s].freeze,
9
+ install: %w[prefer-dedupe package-lock-only cpu=q libc=e os=q].freeze,
10
+ install_base: %w[ignore-scripts install-links strict-peer-deps include=b omit=b install-strategy=b].freeze,
11
+ install_no: %w[audit bin-links fund package-lock].freeze,
12
+ install_as: %w[foreground-scripts g|global no-save save save-bundle save-dev E|save-exact save-optional
13
+ save-peer S|save-prod].freeze,
14
+ pack: %w[json ignore-scripts pack-destination=p].freeze
15
+ }.freeze
16
+ OPT_PNPM = {
17
+ common: %w[aggregate-output color no-color stream use-stderr C|dir=p loglevel=b w|workspace-root].freeze,
18
+ install: %w[fix-lockfile force ignore-pnpmfile ignore-workspace lockfile-only merge-git-branch-lockfiles
19
+ no-hoist no-lockfile no-optional prefer-frozen-lockfile resolution-only shamefully-hoist
20
+ side-effects-cache side-effects-cache-readonly s|silent strict-peer-dependencies
21
+ use-running-store-server use-store-server child-concurrency=i hoist-pattern=q lockfile-dir=p
22
+ modules-dir=p network-concurrency=i package-import-method=b public-hoist-pattern=q
23
+ reporter=b].freeze,
24
+ install_base: %w[global-dir ignore-scripts offline prefer-offline store-dir=p virtual-store-dir=p].freeze,
25
+ install_no: %w[frozen-lockfile verify-store-integrity].freeze,
26
+ install_as: %w[D|dev fail-if-no-match global-dir no-optional P|prod r|recursive
27
+ changed-files-ignore-pattern=q filter=q filter-prod=q test-pattern=q].freeze,
28
+ update: %w[global interactive latest depth=i].freeze,
29
+ dedupe: %w[check].freeze,
30
+ pack: %w[json pack-destination=p pack-gzip-level=i].freeze
31
+ }.freeze
32
+ OPT_YARN = {
33
+ common: %w[no-default-rc s|silent verbose cwd=p use-yarnrc=p].freeze,
34
+ install: %w[A|audit g|global S|save D|save-dev E|save-exact P|save-peer O|save-optional T|save-tilde].freeze,
35
+ install_base: %w[check-files disable-pnp enable-pnp flat focus force frozen-lockfile har ignore-platform
36
+ ignore-engines ignore-optional ignore-scripts json link-duplicates no-bin-links no-lockfile
37
+ no-node-version-check no-progress non-interactive offline pnp prefer-offline prod
38
+ pure-lockfile skip-integrity-check strict-semver update-checksums cache-folder=p emoji=b?
39
+ global-folder=p https-proxy=q link-folder=p modules-folder=p mutex=q network-concurrency=i
40
+ network-timeout=i preferred-cache-folder=p production=e? proxy=q otp=e registry=q
41
+ scripts-prepend-node-path=e?].freeze,
42
+ update: %w[A|audit C|caret E|exact L|latest T|tilde P|pattern=q S|scope=e].freeze
43
+ }.freeze
44
+ OPT_BERRY = {
45
+ install: %w[check-cache check-resolutions immutable immutable-cache inline-builds json refresh-lockfile
46
+ mode=e].freeze,
47
+ update: %w[C|caret E|exact F|fixed interactive T|tilde R|recursive mode=e].freeze,
48
+ dedupe: %w[check json mode=e strategy=b].freeze,
49
+ pack: %w[n|dry-run install-if-needed json o|out=p].freeze
50
+ }.freeze
51
+ private_constant :OPT_NPM, :OPT_PNPM, :OPT_YARN, :OPT_BERRY
52
+
7
53
  class << self
8
54
  def populate(*); end
9
55
 
10
56
  def tasks
11
- [:outdated].freeze
57
+ %i[outdated update publish].freeze
12
58
  end
13
59
 
14
60
  def batchargs
@@ -35,12 +81,13 @@ module Squared
35
81
  end
36
82
 
37
83
  @@tasks[ref] = {
38
- 'install' => %i[force frozen dedupe].freeze,
84
+ 'package' => %i[install dedupe update].freeze,
39
85
  'outdated' => %i[major minor patch].freeze,
40
86
  'bump' => %i[version major minor patch].freeze,
87
+ 'publish' => %i[latest tag].freeze,
41
88
  'add' => nil,
42
- 'update' => nil,
43
- 'run' => nil
89
+ 'run' => nil,
90
+ 'pack' => nil
44
91
  }.freeze
45
92
 
46
93
  def initialize(*, **kwargs)
@@ -72,7 +119,7 @@ module Squared
72
119
  case action
73
120
  when 'add'
74
121
  format_desc action, nil, 'save?=prod|dev|optional|peer,name+'
75
- task action, [:save, :name] do |_, args|
122
+ task action, [:save] do |_, args|
76
123
  save = param_guard(action, 'save', args: args, key: :save)
77
124
  if save.start_with?('=')
78
125
  exact = true
@@ -80,12 +127,13 @@ module Squared
80
127
  end
81
128
  case save
82
129
  when 'prod', 'dev', 'optional', 'peer'
83
- name = param_guard(action, 'name', args: args.to_a.drop(1))
130
+ packages = args.to_a.drop(1)
84
131
  else
85
132
  save = 'prod'
86
- name = param_guard(action, 'name', args: args.to_a)
133
+ packages = args.to_a
87
134
  end
88
- depend(:add, packages: name, save: save, exact: exact)
135
+ param_guard(action, 'name', args: packages)
136
+ depend(:add, packages: packages, save: save, exact: exact)
89
137
  end
90
138
  when 'run'
91
139
  next if (list = read_scripts).empty?
@@ -111,25 +159,25 @@ module Squared
111
159
  end
112
160
  end
113
161
  end
114
- when 'update'
115
- format_desc action, nil, 'packages*'
162
+ when 'pack'
163
+ format_desc action, nil, 'opts*'
116
164
  task action do |_, args|
117
- update args.to_a
165
+ pack args.to_a
118
166
  end
119
167
  end
120
168
  else
121
169
  namespace action do
122
170
  flags.each do |flag|
123
171
  case action
124
- when 'install'
125
- format_desc action, flag
126
- task flag do
127
- depend flag
128
- end
129
172
  when 'outdated'
130
173
  format_desc(action, flag, %w[prune interactive dry-run].freeze, arg: 'opts?')
131
174
  task flag do |_, args|
132
- outdated(flag, opts: args.to_a)
175
+ outdated flag, args.to_a
176
+ end
177
+ when 'package'
178
+ format_desc(action, flag, 'opts*', after: flag == :dedupe ? nil : 'names*')
179
+ task flag do |_, args|
180
+ package flag, args.to_a
133
181
  end
134
182
  when 'bump'
135
183
  if flag == :version
@@ -144,6 +192,24 @@ module Squared
144
192
  bump flag
145
193
  end
146
194
  end
195
+ when 'publish'
196
+ format_desc(action, flag, 'otp?,dry-run?=true', before: flag == :tag ? 'tag' : nil)
197
+ task flag do |_, args|
198
+ if flag == :latest
199
+ otp, dryrun = args.to_a
200
+ else
201
+ args = param_guard(action, flag, args: args.to_a)
202
+ tag, otp, dryrun = args
203
+ end
204
+ check = ->(val) { val == 'dry-run' || val == 'true' }
205
+ if check.(otp)
206
+ dryrun = true
207
+ otp = nil
208
+ elsif dryrun
209
+ dryrun = check.(dryrun)
210
+ end
211
+ publish(flag, otp: otp, tag: tag, dryrun: dryrun)
212
+ end
147
213
  end
148
214
  end
149
215
  end
@@ -152,8 +218,8 @@ module Squared
152
218
  end
153
219
  end
154
220
 
155
- def copy(from: 'build', into: 'node_modules', workspace: false, scope: nil,
156
- also: nil, create: nil, link: false, force: false, override: false, **kwargs)
221
+ def copy(from: 'build', into: 'node_modules', workspace: false, include: nil, exclude: nil, scope: nil,
222
+ also: nil, create: nil, link: false, force: false, override: false)
157
223
  return if @copy == false
158
224
 
159
225
  if @copy && !override
@@ -163,15 +229,12 @@ module Squared
163
229
  into = @copy[:into] if @copy.key?(:into)
164
230
  workspace = @copy[:workspace] if @copy.key?(:workspace)
165
231
  link = @copy[:link] if @copy.key?(:link)
166
- force = @copy[:force] if @copy.key?(:force)
232
+ force = @copy[:force] if @copy.key?(:link)
167
233
  glob = @copy[:include]
168
234
  exclude = @copy[:exclude]
169
235
  scope = @copy[:scope]
170
236
  also = @copy[:also]
171
237
  create = @copy[:create]
172
- else
173
- glob = kwargs[:include]
174
- exclude = kwargs[:exclude]
175
238
  end
176
239
  items = []
177
240
  items << @workspace.home if build? && path != @workspace.home && @workspace.home?
@@ -250,77 +313,42 @@ module Squared
250
313
  on :last, :copy
251
314
  end
252
315
 
253
- def depend(flag = nil, sync: invoked_sync?('depend', flag), packages: [], save: nil, exact: nil)
316
+ def depend(flag = nil, *, sync: invoked_sync?('depend', flag), packages: [], save: nil, exact: nil, **)
254
317
  if @depend && !flag
255
318
  super
256
319
  elsif outdated?
320
+ return update if !flag && env('NODE_UPDATE')
321
+
257
322
  if (yarn = dependtype(:yarn)) > 0
258
323
  cmd = session 'yarn'
259
324
  if flag == :add
260
325
  cmd << 'add'
261
326
  cmd << "--#{save}" unless save == 'prod'
262
327
  cmd << '--exact' if exact
263
- elsif yarn > 1
264
- if flag == :dedupe
265
- cmd << 'dedupe'
266
- else
267
- cmd << 'install' << if flag == :force
268
- '--check-cache'
269
- elsif flag == :frozen
270
- '--immutable'
271
- end
272
- end
273
328
  else
274
- cmd << 'install' << if flag == :force
275
- '--force'
276
- elsif flag == :frozen
277
- '--frozen-lockfile'
278
- end
279
- cmd << '--production' if flag && prod?
280
- cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
329
+ cmd << 'install'
330
+ cmd << '--ignore-engines' if yarn == 1 && !option('ignore-engines', equals: '0')
281
331
  end
282
332
  elsif pnpm?
283
333
  cmd = session 'pnpm'
284
- case flag
285
- when :add
334
+ if flag == :add
286
335
  cmd << 'add'
287
336
  cmd << "--save-#{save}"
288
337
  cmd << '--save-exact' if exact
289
- when :dedupe
290
- cmd << 'dedupe'
291
338
  else
292
- cmd << 'install' << if flag == :force
293
- '--force'
294
- elsif flag == :frozen
295
- '--frozen-lockfile'
296
- end
339
+ cmd << 'install'
297
340
  end
298
- cmd << '--prod' if flag && prod?
299
341
  if (val = option('public-hoist-pattern', ignore: false))
300
342
  split_escape(val).each { |opt| cmd << shell_option('public-hoist-pattern', opt) }
301
343
  end
302
344
  cmd << '--ignore-workspace' if env('NODE_WORKSPACES', equals: '0')
303
345
  append_nocolor
304
346
  else
305
- cmd = session 'npm'
306
- case flag
307
- when :add
308
- cmd << 'install'
347
+ cmd = session 'npm', 'install'
348
+ if flag == :add
309
349
  cmd << "--save-#{save}"
310
350
  cmd << '--save-exact' if exact
311
- when :dedupe
312
- cmd << 'dedupe'
313
- else
314
- cmd << 'install' << if flag == :force
315
- '--force'
316
- elsif flag == :frozen
317
- '--package-lock-only'
318
- end
319
- end
320
- if flag == :add
321
351
  cmd.merge(packages.map { |pkg| shell_escape(pkg) })
322
- elsif flag && prod?
323
- cmd << '--omit=dev'
324
352
  end
325
353
  cmd << '--workspaces=false' if env('NODE_WORKSPACES', equals: '0')
326
354
  cmd << '--package-lock=false' if option('package-lock', equals: '0')
@@ -331,7 +359,7 @@ module Squared
331
359
  end
332
360
  end
333
361
 
334
- def outdated(flag = nil, sync: invoked_sync?('outdated', flag), opts: [])
362
+ def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
335
363
  dryrun = opts.include?('dry-run')
336
364
  if pnpm? && read_packagemanager(version: '7.15', update: true)
337
365
  cmd = session 'pnpm', 'outdated'
@@ -340,8 +368,10 @@ module Squared
340
368
  cmd = session 'npm', 'outdated'
341
369
  dryrun ||= dryrun?('npm')
342
370
  end
343
- log.info cmd.to_s
344
- on :first, :outdated unless dryrun
371
+ unless dryrun
372
+ log.info cmd.to_s
373
+ on :first, :outdated
374
+ end
345
375
  banner = format_banner(cmd.temp(dryrun ? ' --dry-run' : nil))
346
376
  print_item banner if sync
347
377
  begin
@@ -350,9 +380,10 @@ module Squared
350
380
  json = JSON.parse(doc)
351
381
  rescue StandardError => e
352
382
  log.error e
353
- ret = on(:error, :outdated, e)
354
- raise if exception && ret != true
355
-
383
+ unless dryrun
384
+ ret = on(:error, :outdated, e)
385
+ raise if exception && ret != true
386
+ end
356
387
  warn log_message(Logger::WARN, e) if warning?
357
388
  return
358
389
  else
@@ -403,7 +434,7 @@ module Squared
403
434
  index = if a != c
404
435
  1
405
436
  elsif b != d
406
- a == '0' ? 1 : 3
437
+ 3
407
438
  else
408
439
  5
409
440
  end
@@ -437,8 +468,7 @@ module Squared
437
468
  col2 = size_col.(found, 1) + 4
438
469
  found.each_with_index do |item, i|
439
470
  a, b, c, d, e = item
440
- f = inter && (rev != :major || e || semmajor?(item[5], item[6]))
441
- if f && !confirm_outdated(a, c, d, e)
471
+ if inter && (rev != :major || e || semmajor?(item[5], item[6])) && !confirm_outdated(a, c, d, e)
442
472
  cur = -1
443
473
  else
444
474
  cur = modified
@@ -475,7 +505,7 @@ module Squared
475
505
  modified = -1
476
506
  footer.(0, found.size)
477
507
  File.write(dependfile, doc)
478
- commit(:add, ['package.json'], pass: true)
508
+ commit(:add, refs: ['package.json'], pass: true)
479
509
  install if opts.include?('prune')
480
510
  end
481
511
  elsif !avail.empty?
@@ -501,6 +531,102 @@ module Squared
501
531
  on :last, :outdated unless dryrun
502
532
  end
503
533
 
534
+ def update(*)
535
+ package 'update'
536
+ end
537
+
538
+ def publish(flag = nil, *, sync: invoked_sync?('publish', flag), otp: nil, tag: nil, dryrun: nil, **)
539
+ if read_packagemanager(:private)
540
+ warn log_message(Logger::WARN, 'invalid task "publish"', subject: name, hint: 'private') if warning?
541
+ return
542
+ end
543
+ return unless version
544
+
545
+ cmd = session 'npm', 'publish'
546
+ otp = option('otp') if otp.nil?
547
+ tag = option('tag') if tag.nil?
548
+ dryrun = dryrun?('npm') if dryrun.nil?
549
+ cmd << basic_option('otp', otp) if otp
550
+ cmd << shell_option('tag', tag) if tag
551
+ if verbose
552
+ if dryrun
553
+ cmd << '--dry-run'
554
+ else
555
+ log.info cmd.to_s
556
+ end
557
+ unless sync
558
+ on :first, :publish unless dryrun
559
+ pwd_set(from: :publish, dryrun: dryrun) do
560
+ require 'open3'
561
+ banner = format_banner(cmd.to_s)
562
+ Open3.popen2e(cmd.done) do |_, out|
563
+ write_lines(out, banner: banner, sub: npmnotice + [
564
+ { pat: /^(.+)(Tarball .+)$/, styles: :blue, index: 2 }
565
+ ])
566
+ end
567
+ end
568
+ on :last, :publish unless dryrun
569
+ return
570
+ end
571
+ elsif dryrun
572
+ return
573
+ end
574
+ run(from: :publish, sync: sync)
575
+ end
576
+
577
+ def package(flag, opts = [])
578
+ if (yarn = dependtype(:yarn)) > 0
579
+ cmd = session 'yarn', if flag == :update
580
+ flag = yarn == 1 ? 'upgrade' : 'up'
581
+ else
582
+ flag
583
+ end
584
+ out = option_sanitize(opts, if yarn == 1
585
+ OPT_PNPM[:install_base] + OPT_YARN.fetch(flag, []) + OPT_YARN[:common]
586
+ else
587
+ OPT_BERRY[flag]
588
+ end).first
589
+ append_loglevel
590
+ option_clear out
591
+ elsif pnpm?
592
+ cmd = session 'pnpm', flag
593
+ list = OPT_PNPM[:install_base] + OPT_PNPM.fetch(flag, []) + OPT_PNPM[:common]
594
+ list += OPT_PNPM[:install_as] unless flag == :dedupe
595
+ out = option_sanitize(opts, list, no: OPT_PNPM[:"#{flag}_no"]).first
596
+ append_nocolor
597
+ append_loglevel
598
+ option_clear out
599
+ else
600
+ cmd = session 'npm', flag
601
+ list = OPT_NPM[:install_base] + OPT_NPM.fetch(flag, []) + OPT_NPM[:common]
602
+ list += OPT_NPM[:install_as] unless flag == :dedupe
603
+ opts, pat = option_sanitize(opts, list, no: OPT_NPM[:install_no])
604
+ out = []
605
+ err = []
606
+ opts.each do |opt|
607
+ if opt =~ pat
608
+ case $1
609
+ when 'w', 'workspace'
610
+ cmd << (%r{[\\/]}.match?($2) ? quote_option($1, basepath($2)) : shell_option($1, $2))
611
+ end
612
+ elsif opt.include?('=')
613
+ err << opt
614
+ else
615
+ out << opt
616
+ end
617
+ end
618
+ append_nocolor
619
+ append_loglevel
620
+ if flag == :dedupe
621
+ option_clear out
622
+ else
623
+ append_value(out, escape: true)
624
+ end
625
+ option_clear err
626
+ end
627
+ run(from: :"package:#{flag}")
628
+ end
629
+
504
630
  def bump(flag, val = nil)
505
631
  return unless (cur = version)
506
632
 
@@ -555,43 +681,43 @@ module Squared
555
681
  end
556
682
  end
557
683
 
558
- def update(pkgs = [])
559
- if (yarn = dependtype(:yarn)) > 0
560
- cmd = session 'yarn'
561
- if yarn > 1
562
- cmd << 'up'
563
- else
564
- cmd << 'upgrade'
565
- cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
566
- end
567
- elsif pnpm?
568
- cmd = session 'pnpm', 'update'
569
- cmd << '--prod' if prod?
570
- append_nocolor
684
+ def pack(opts = [])
685
+ return unless version
686
+
687
+ cmd = session dependbin, 'pack'
688
+ if dependtype(:yarn) > 1
689
+ out = option_sanitize(opts, OPT_BERRY[:pack]).first
690
+ cmd << quote_option('out', Pathname.pwd.join("#{project}-#{version}.tgz")) unless session_arg?('out')
571
691
  else
572
- cmd = session 'npm', 'update'
573
- cmd << '--omit=dev' if prod?
574
- append_nocolor
692
+ out = option_sanitize(opts, pnpm? ? OPT_PNPM[:pack] : OPT_NPM[:pack] + OPT_NPM[:common]).first
693
+ cmd << quote_option('pack-destination', Dir.pwd) unless session_arg?('pack-destination')
575
694
  end
576
- append_loglevel
577
- append_value pkgs
578
- run
695
+ option_clear out
696
+ run(from: :pack)
579
697
  end
580
698
 
581
- def compose(opts, flags = nil, script: false, from: nil)
582
- return unless opts && script
699
+ def compose(opts, flags = nil, script: false, args: nil, from: :build, **)
700
+ return unless opts
583
701
 
584
- ret = session dependbin, 'run', flags
585
- append_loglevel
586
- case opts
587
- when Enumerable
588
- ret.merge(opts.to_a)
589
- when String
590
- ret << opts
702
+ if script
703
+ ret = session dependbin, 'run'
704
+ raise_error("#{dependbin} run script: #{from}", hint: "given #{opts}") unless append_any(opts)
705
+ append_any flags if flags
706
+ append_loglevel
707
+ append_any(args, delim: true) if args
708
+ ret
591
709
  else
592
- raise_error("#{dependbin} script name: given #{opts}", hint: from)
710
+ case opts
711
+ when String
712
+ opts
713
+ when Hash
714
+ append_hash(opts).join(' ')
715
+ when Enumerable
716
+ opts.to_a.join(' ')
717
+ else
718
+ raise_error("#{project}: #{from}", hint: "given #{opts}")
719
+ end
593
720
  end
594
- ret
595
721
  end
596
722
 
597
723
  def depend?
@@ -606,8 +732,8 @@ module Squared
606
732
  dependfile.exist?
607
733
  end
608
734
 
609
- def refresh?
610
- !Node.prod?
735
+ def update?
736
+ outdated?
611
737
  end
612
738
 
613
739
  def yarn?
@@ -690,10 +816,11 @@ module Squared
690
816
  def read_packagemanager(key = nil, version: nil, update: false)
691
817
  if @pm[:_].nil? || update
692
818
  doc = JSON.parse(dependfile.read)
693
- @pm[:_] = (val = doc['packageManager']) ? val[0..(val.index('+') || 0) - 1] : false
819
+ @pm[:_] = (val = doc['packageManager']) ? val[0, val.index('+') || val.size] : false
694
820
  @pm[:name] = doc['name']
695
821
  @pm[:scripts] = doc['scripts']
696
822
  @pm[:version] = doc['version']
823
+ @pm[:private] = doc['private']
697
824
  @pm[:workspaces] = doc['workspaces']
698
825
  end
699
826
  rescue StandardError => e
@@ -762,10 +889,10 @@ module Squared
762
889
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
763
890
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
764
891
  e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
765
- Common::Prompt.confirm("Upgrade to #{a}? #{b}#{e} [#{c}] ", d, timeout: 60)
892
+ Common::Prompt.confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d, timeout: 60)
766
893
  end
767
894
 
768
- def dryrun?(prefix = dependbin)
895
+ def dryrun?(prefix = dependbin, **)
769
896
  super || !option('dry-run', prefix: prefix).nil?
770
897
  end
771
898
 
@@ -780,6 +907,15 @@ module Squared
780
907
  def dependext
781
908
  'package.json' if parent&.has?('outdated', Node.ref)
782
909
  end
910
+
911
+ def npmnotice
912
+ [
913
+ { pat: /^(npm error )(code|\d+)(.+)$/, styles: :cyan, index: 2 },
914
+ { pat: /^(npm )(error)(.*)$/, styles: :red, index: 2 },
915
+ { pat: /^(npm )(notice)(.*)$/, styles: :cyan, index: 2 },
916
+ { pat: /^(npm )(.+)$/, styles: :bold }
917
+ ]
918
+ end
783
919
  end
784
920
 
785
921
  Application.implement Node