squared 0.2.2 → 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
@@ -247,77 +313,42 @@ module Squared
247
313
  on :last, :copy
248
314
  end
249
315
 
250
- 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, **)
251
317
  if @depend && !flag
252
318
  super
253
319
  elsif outdated?
320
+ return update if !flag && env('NODE_UPDATE')
321
+
254
322
  if (yarn = dependtype(:yarn)) > 0
255
323
  cmd = session 'yarn'
256
324
  if flag == :add
257
325
  cmd << 'add'
258
326
  cmd << "--#{save}" unless save == 'prod'
259
327
  cmd << '--exact' if exact
260
- elsif yarn > 1
261
- if flag == :dedupe
262
- cmd << 'dedupe'
263
- else
264
- cmd << 'install' << if flag == :force
265
- '--check-cache'
266
- elsif flag == :frozen
267
- '--immutable'
268
- end
269
- end
270
328
  else
271
- cmd << 'install' << if flag == :force
272
- '--force'
273
- elsif flag == :frozen
274
- '--frozen-lockfile'
275
- end
276
- cmd << '--production' if flag && prod?
277
- cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
329
+ cmd << 'install'
330
+ cmd << '--ignore-engines' if yarn == 1 && !option('ignore-engines', equals: '0')
278
331
  end
279
332
  elsif pnpm?
280
333
  cmd = session 'pnpm'
281
- case flag
282
- when :add
334
+ if flag == :add
283
335
  cmd << 'add'
284
336
  cmd << "--save-#{save}"
285
337
  cmd << '--save-exact' if exact
286
- when :dedupe
287
- cmd << 'dedupe'
288
338
  else
289
- cmd << 'install' << if flag == :force
290
- '--force'
291
- elsif flag == :frozen
292
- '--frozen-lockfile'
293
- end
339
+ cmd << 'install'
294
340
  end
295
- cmd << '--prod' if flag && prod?
296
341
  if (val = option('public-hoist-pattern', ignore: false))
297
342
  split_escape(val).each { |opt| cmd << shell_option('public-hoist-pattern', opt) }
298
343
  end
299
344
  cmd << '--ignore-workspace' if env('NODE_WORKSPACES', equals: '0')
300
345
  append_nocolor
301
346
  else
302
- cmd = session 'npm'
303
- case flag
304
- when :add
305
- cmd << 'install'
347
+ cmd = session 'npm', 'install'
348
+ if flag == :add
306
349
  cmd << "--save-#{save}"
307
350
  cmd << '--save-exact' if exact
308
- when :dedupe
309
- cmd << 'dedupe'
310
- else
311
- cmd << 'install' << if flag == :force
312
- '--force'
313
- elsif flag == :frozen
314
- '--package-lock-only'
315
- end
316
- end
317
- if flag == :add
318
351
  cmd.merge(packages.map { |pkg| shell_escape(pkg) })
319
- elsif flag && prod?
320
- cmd << '--omit=dev'
321
352
  end
322
353
  cmd << '--workspaces=false' if env('NODE_WORKSPACES', equals: '0')
323
354
  cmd << '--package-lock=false' if option('package-lock', equals: '0')
@@ -328,7 +359,7 @@ module Squared
328
359
  end
329
360
  end
330
361
 
331
- def outdated(flag = nil, sync: invoked_sync?('outdated', flag), opts: [])
362
+ def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
332
363
  dryrun = opts.include?('dry-run')
333
364
  if pnpm? && read_packagemanager(version: '7.15', update: true)
334
365
  cmd = session 'pnpm', 'outdated'
@@ -337,8 +368,10 @@ module Squared
337
368
  cmd = session 'npm', 'outdated'
338
369
  dryrun ||= dryrun?('npm')
339
370
  end
340
- log.info cmd.to_s
341
- on :first, :outdated unless dryrun
371
+ unless dryrun
372
+ log.info cmd.to_s
373
+ on :first, :outdated
374
+ end
342
375
  banner = format_banner(cmd.temp(dryrun ? ' --dry-run' : nil))
343
376
  print_item banner if sync
344
377
  begin
@@ -347,9 +380,10 @@ module Squared
347
380
  json = JSON.parse(doc)
348
381
  rescue StandardError => e
349
382
  log.error e
350
- ret = on(:error, :outdated, e)
351
- raise if exception && ret != true
352
-
383
+ unless dryrun
384
+ ret = on(:error, :outdated, e)
385
+ raise if exception && ret != true
386
+ end
353
387
  warn log_message(Logger::WARN, e) if warning?
354
388
  return
355
389
  else
@@ -471,7 +505,7 @@ module Squared
471
505
  modified = -1
472
506
  footer.(0, found.size)
473
507
  File.write(dependfile, doc)
474
- commit(:add, ['package.json'], pass: true)
508
+ commit(:add, refs: ['package.json'], pass: true)
475
509
  install if opts.include?('prune')
476
510
  end
477
511
  elsif !avail.empty?
@@ -497,6 +531,102 @@ module Squared
497
531
  on :last, :outdated unless dryrun
498
532
  end
499
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
+
500
630
  def bump(flag, val = nil)
501
631
  return unless (cur = version)
502
632
 
@@ -551,43 +681,43 @@ module Squared
551
681
  end
552
682
  end
553
683
 
554
- def update(pkgs = [])
555
- if (yarn = dependtype(:yarn)) > 0
556
- cmd = session 'yarn'
557
- if yarn > 1
558
- cmd << 'up'
559
- else
560
- cmd << 'upgrade'
561
- cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
562
- end
563
- elsif pnpm?
564
- cmd = session 'pnpm', 'update'
565
- cmd << '--prod' if prod?
566
- 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')
567
691
  else
568
- cmd = session 'npm', 'update'
569
- cmd << '--omit=dev' if prod?
570
- 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')
571
694
  end
572
- append_loglevel
573
- append_value pkgs
574
- run
695
+ option_clear out
696
+ run(from: :pack)
575
697
  end
576
698
 
577
- def compose(opts, flags = nil, script: false, from: :build)
578
- return unless opts && script && from == :build
699
+ def compose(opts, flags = nil, script: false, args: nil, from: :build, **)
700
+ return unless opts
579
701
 
580
- ret = session dependbin, 'run', flags
581
- append_loglevel
582
- case opts
583
- when Enumerable
584
- ret.merge(opts.to_a)
585
- when String
586
- 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
587
709
  else
588
- raise_error("#{dependbin} script name", hint: opts.nil? ? 'missing' : 'invalid')
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
589
720
  end
590
- ret
591
721
  end
592
722
 
593
723
  def depend?
@@ -602,6 +732,10 @@ module Squared
602
732
  dependfile.exist?
603
733
  end
604
734
 
735
+ def update?
736
+ outdated?
737
+ end
738
+
605
739
  def yarn?
606
740
  (@pm[:yarn] ||= if basepath('yarn.lock', ascend: dependext).exist?
607
741
  if (rc = basepath('.yarnrc.yml', ascend: dependext)).exist?
@@ -682,10 +816,11 @@ module Squared
682
816
  def read_packagemanager(key = nil, version: nil, update: false)
683
817
  if @pm[:_].nil? || update
684
818
  doc = JSON.parse(dependfile.read)
685
- @pm[:_] = (val = doc['packageManager']) ? val[0..(val.index('+') || 0) - 1] : false
819
+ @pm[:_] = (val = doc['packageManager']) ? val[0, val.index('+') || val.size] : false
686
820
  @pm[:name] = doc['name']
687
821
  @pm[:scripts] = doc['scripts']
688
822
  @pm[:version] = doc['version']
823
+ @pm[:private] = doc['private']
689
824
  @pm[:workspaces] = doc['workspaces']
690
825
  end
691
826
  rescue StandardError => e
@@ -754,10 +889,10 @@ module Squared
754
889
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
755
890
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
756
891
  e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
757
- 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)
758
893
  end
759
894
 
760
- def dryrun?(prefix = dependbin)
895
+ def dryrun?(prefix = dependbin, **)
761
896
  super || !option('dry-run', prefix: prefix).nil?
762
897
  end
763
898
 
@@ -772,6 +907,15 @@ module Squared
772
907
  def dependext
773
908
  'package.json' if parent&.has?('outdated', Node.ref)
774
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
775
919
  end
776
920
 
777
921
  Application.implement Node