squared 0.2.5 → 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
@@ -474,7 +505,7 @@ module Squared
474
505
  modified = -1
475
506
  footer.(0, found.size)
476
507
  File.write(dependfile, doc)
477
- commit(:add, ['package.json'], pass: true)
508
+ commit(:add, refs: ['package.json'], pass: true)
478
509
  install if opts.include?('prune')
479
510
  end
480
511
  elsif !avail.empty?
@@ -500,6 +531,102 @@ module Squared
500
531
  on :last, :outdated unless dryrun
501
532
  end
502
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
+
503
630
  def bump(flag, val = nil)
504
631
  return unless (cur = version)
505
632
 
@@ -554,43 +681,43 @@ module Squared
554
681
  end
555
682
  end
556
683
 
557
- def update(pkgs = [])
558
- if (yarn = dependtype(:yarn)) > 0
559
- cmd = session 'yarn'
560
- if yarn > 1
561
- cmd << 'up'
562
- else
563
- cmd << 'upgrade'
564
- cmd << '--ignore-engines' unless option('ignore-engines', equals: '0')
565
- end
566
- elsif pnpm?
567
- cmd = session 'pnpm', 'update'
568
- cmd << '--prod' if prod?
569
- 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')
570
691
  else
571
- cmd = session 'npm', 'update'
572
- cmd << '--omit=dev' if prod?
573
- 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')
574
694
  end
575
- append_loglevel
576
- append_value pkgs
577
- run
695
+ option_clear out
696
+ run(from: :pack)
578
697
  end
579
698
 
580
- def compose(opts, flags = nil, script: false, from: :build)
581
- return unless opts && script && from == :build
699
+ def compose(opts, flags = nil, script: false, args: nil, from: :build, **)
700
+ return unless opts
582
701
 
583
- ret = session dependbin, 'run', flags
584
- append_loglevel
585
- case opts
586
- when Enumerable
587
- ret.merge(opts.to_a)
588
- when String
589
- 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
590
709
  else
591
- 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
592
720
  end
593
- ret
594
721
  end
595
722
 
596
723
  def depend?
@@ -605,6 +732,10 @@ module Squared
605
732
  dependfile.exist?
606
733
  end
607
734
 
735
+ def update?
736
+ outdated?
737
+ end
738
+
608
739
  def yarn?
609
740
  (@pm[:yarn] ||= if basepath('yarn.lock', ascend: dependext).exist?
610
741
  if (rc = basepath('.yarnrc.yml', ascend: dependext)).exist?
@@ -685,10 +816,11 @@ module Squared
685
816
  def read_packagemanager(key = nil, version: nil, update: false)
686
817
  if @pm[:_].nil? || update
687
818
  doc = JSON.parse(dependfile.read)
688
- @pm[:_] = (val = doc['packageManager']) ? val[0..(val.index('+') || 0) - 1] : false
819
+ @pm[:_] = (val = doc['packageManager']) ? val[0, val.index('+') || val.size] : false
689
820
  @pm[:name] = doc['name']
690
821
  @pm[:scripts] = doc['scripts']
691
822
  @pm[:version] = doc['version']
823
+ @pm[:private] = doc['private']
692
824
  @pm[:workspaces] = doc['workspaces']
693
825
  end
694
826
  rescue StandardError => e
@@ -757,10 +889,10 @@ module Squared
757
889
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
758
890
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
759
891
  e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
760
- 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)
761
893
  end
762
894
 
763
- def dryrun?(prefix = dependbin)
895
+ def dryrun?(prefix = dependbin, **)
764
896
  super || !option('dry-run', prefix: prefix).nil?
765
897
  end
766
898
 
@@ -775,6 +907,15 @@ module Squared
775
907
  def dependext
776
908
  'package.json' if parent&.has?('outdated', Node.ref)
777
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
778
919
  end
779
920
 
780
921
  Application.implement Node