cocoapods-lynx-library 4.0.1 → 4.0.2.pre.alpha.1

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lynx/library/autolink.rb +173 -6
  3. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3136b837deb630695dd833ab399b881520a14bf7fc414cd40b4bb50e9701a79f
4
- data.tar.gz: 19123c9161c812dfb4f863876f44d2eb2b8491a46119bcfa48c15e24e355aaec
3
+ metadata.gz: 6be5d0eb274376666a18c12b050b7fe962b50363d1a09d64c797002443ed3764
4
+ data.tar.gz: f6efdd409ec96cd26028ee64e710ba0a9ace426c055d1d0c441a4603afb9d5fa
5
5
  SHA512:
6
- metadata.gz: 5dea83a634bf0ab72ee235612bee82c2be20f82c0f203f56eec65ea5ee22c2a673ba3f446bca5d5645d9734242d9107e47b5678f65a493f35cf17e5619f6b307
7
- data.tar.gz: f814f70ab20e8462077c6708540d680037b44470eb29ceb6d4439134f4b000136caec0b4b33297edd04431484b94b9f32be5f3dd21e7a6d98b2e4d75e6496c89
6
+ metadata.gz: 770228d8fdf4bf28bb606e29bd9e0d5b36d57417852eebd4861b97fabbec8202329709384e71d1c8da0609364bb05b74b0506c2539ba2730a4527979b61065dd
7
+ data.tar.gz: 15b13513e55f83aa3032c204a53d2651bcd2ae8ef2e38a7d9d959066d1e444487a4566867ad79cba6efedb106ff9e607b0c3e0ca8ecc7ec8a942d3ffd75adf72
@@ -7,20 +7,29 @@ require 'json'
7
7
 
8
8
  module Lynx
9
9
  module Library
10
- LibraryInfo = Struct.new(:npm_name, :package_dir, :manifest_file, :source_dir, :podspec_path)
10
+ LibraryInfo = Struct.new(
11
+ :npm_name, :package_dir, :manifest_file, :source_dir, :podspec_path, :node_api_addons)
11
12
  ComponentInfo = Struct.new(:kind, :name, :class_name)
13
+ NodeApiAddonInfo = Struct.new(
14
+ :name, :pod_name, :podspec_path, :addon_use_header, :required)
12
15
 
13
16
  class Autolink
14
17
  REGISTRY_CLASS_NAME = 'LynxGeneratedLibraryRegistry'
18
+ ADDON_USE_SOURCE_NAME = 'LynxGeneratedNodeAPIAddonUse.mm'
19
+ ADDON_NAME_PATTERN = /\A[A-Za-z_][A-Za-z0-9_]*\z/
15
20
 
16
21
  class << self
17
22
  def install!(podfile, options = {})
18
23
  start_dir = File.expand_path(options[:root] || Dir.pwd)
19
24
  output_dir = File.expand_path(options[:output_dir] || 'generated/lynx-library', start_dir)
20
25
  libraries = scan(start_dir)
26
+ added_pods = []
21
27
  libraries.each do |library|
22
28
  pod_name = pod_name_from_podspec(library.podspec_path)
23
- podfile.pod pod_name, :path => File.dirname(library.podspec_path)
29
+ add_pod_once(podfile, added_pods, pod_name, File.dirname(library.podspec_path))
30
+ library.node_api_addons.each do |addon|
31
+ add_pod_once(podfile, added_pods, addon.pod_name, File.dirname(addon.podspec_path))
32
+ end
24
33
  end
25
34
  generate_registry(output_dir, libraries)
26
35
  podfile.pod 'LynxLibraryRegistry', :path => output_dir
@@ -36,10 +45,13 @@ module Lynx
36
45
  def generate_registry(output_dir, libraries)
37
46
  FileUtils.mkdir_p(output_dir)
38
47
  components = libraries.flat_map { |library| scan_components(library.source_dir) }
48
+ node_api_addons = libraries.flat_map(&:node_api_addons)
39
49
  File.write(File.join(output_dir, "#{REGISTRY_CLASS_NAME}.h"), header_source)
40
50
  File.write(File.join(output_dir, "#{REGISTRY_CLASS_NAME}.m"),
41
51
  implementation_source(components))
42
- File.write(File.join(output_dir, 'LynxLibraryRegistry.podspec'), podspec_source)
52
+ File.write(File.join(output_dir, ADDON_USE_SOURCE_NAME), addon_use_source(node_api_addons))
53
+ File.write(File.join(output_dir, 'LynxLibraryRegistry.podspec'),
54
+ podspec_source(node_api_addons))
43
55
  components
44
56
  end
45
57
 
@@ -106,14 +118,79 @@ module Lynx
106
118
  raise "No iOS podspec found for #{manifest_file}" unless
107
119
  podspec_path && File.file?(podspec_path)
108
120
 
121
+ node_api_addons = parse_node_api_addons(ios['nodeApiAddons'], package_realpath,
122
+ podspec_path, manifest_file)
123
+
109
124
  npm_name = File.basename(package_dir)
110
125
  parent_name = File.basename(File.dirname(package_dir))
111
126
  npm_name = "#{parent_name}/#{npm_name}" if parent_name.start_with?('@')
112
- LibraryInfo.new(npm_name, package_dir, manifest_file, source_dir, podspec_path)
127
+ LibraryInfo.new(npm_name, package_dir, manifest_file, source_dir, podspec_path,
128
+ node_api_addons)
113
129
  rescue JSON::ParserError => e
114
130
  raise "Failed to parse #{manifest_file}: #{e.message}"
115
131
  end
116
132
 
133
+ def add_pod_once(podfile, added_pods, pod_name, pod_path)
134
+ key = [pod_name, pod_path]
135
+ return if added_pods.include?(key)
136
+
137
+ podfile.pod pod_name, :path => pod_path
138
+ added_pods << key
139
+ end
140
+
141
+ def parse_node_api_addons(addons, package_realpath, default_podspec_path, manifest_file)
142
+ return [] if addons.nil?
143
+ raise "platforms.ios.nodeApiAddons in #{manifest_file} must be an array" unless
144
+ addons.is_a?(Array)
145
+
146
+ addons.each_with_index.map do |addon, index|
147
+ raise "platforms.ios.nodeApiAddons[#{index}] in #{manifest_file} must be an object" unless
148
+ addon.is_a?(Hash)
149
+
150
+ name = addon['name']
151
+ validate_addon_name(name, "platforms.ios.nodeApiAddons[#{index}].name", manifest_file)
152
+ addon_podspec_path = if addon['podspecPath']
153
+ resolve_package_path(package_realpath, addon['podspecPath'],
154
+ manifest_file,
155
+ "nodeApiAddons[#{index}].podspecPath")
156
+ else
157
+ default_podspec_path
158
+ end
159
+ raise "No iOS Node-API addon podspec found for #{manifest_file}" unless
160
+ addon_podspec_path && File.file?(addon_podspec_path)
161
+
162
+ pod_name = addon['podName'] || pod_name_from_podspec(addon_podspec_path)
163
+ addon_use_header = addon['addonUseHeader'] || 'addon_use.h'
164
+ validate_addon_use_header(addon_use_header,
165
+ "platforms.ios.nodeApiAddons[#{index}].addonUseHeader",
166
+ manifest_file)
167
+ required = addon.key?('required') ? !!addon['required'] : true
168
+ NodeApiAddonInfo.new(name.strip, pod_name, addon_podspec_path, addon_use_header,
169
+ required)
170
+ end
171
+ end
172
+
173
+ def validate_addon_name(name, field_name, manifest_file)
174
+ raise "Missing #{field_name} in #{manifest_file}" if name.nil? || name.strip.empty?
175
+
176
+ normalized = name.strip
177
+ return if normalized.length <= 128 && !normalized.include?('..') &&
178
+ normalized.match?(ADDON_NAME_PATTERN)
179
+
180
+ raise "Invalid #{field_name} '#{name}' in #{manifest_file}; " \
181
+ 'expected a C identifier matching [A-Za-z_][A-Za-z0-9_]*'
182
+ end
183
+
184
+ def validate_addon_use_header(header, field_name, manifest_file)
185
+ raise "Missing #{field_name} in #{manifest_file}" if header.nil? || header.strip.empty?
186
+
187
+ normalized = header.strip
188
+ return if !normalized.start_with?('/') && !normalized.include?('..') &&
189
+ normalized.match?(/\A[A-Za-z0-9_\.\/-]+\z/)
190
+
191
+ raise "Invalid #{field_name} '#{header}' in #{manifest_file}"
192
+ end
193
+
117
194
  def pod_name_from_podspec(podspec_path)
118
195
  content = File.read(podspec_path)
119
196
  match = content.match(/\.name\s*=\s*['"]([^'"]+)['"]/)
@@ -223,8 +300,11 @@ module Lynx
223
300
  #import "#{REGISTRY_CLASS_NAME}.h"
224
301
  #import <Lynx/LynxConfig.h>
225
302
 
303
+ extern void LynxGeneratedNodeAPIAddonUse(void);
304
+
226
305
  @implementation #{REGISTRY_CLASS_NAME}
227
306
  - (void)setup:(LynxConfig *)config {
307
+ LynxGeneratedNodeAPIAddonUse();
228
308
  if (config == nil) {
229
309
  return;
230
310
  }
@@ -234,7 +314,91 @@ module Lynx
234
314
  IMPL
235
315
  end
236
316
 
237
- def podspec_source
317
+ def addon_use_source(node_api_addons)
318
+ includes = node_api_addons.uniq { |addon| [addon.pod_name, addon.addon_use_header] }
319
+ .map do |addon|
320
+ header = "#{addon.pod_name}/#{addon.addon_use_header}"
321
+ <<~INCLUDE.chomp
322
+ #if __has_include(<#{header}>)
323
+ #include <#{header}>
324
+ #endif
325
+ INCLUDE
326
+ end.join("\n\n")
327
+ addon_register_declarations = node_api_addons.map(&:name).uniq.map do |name|
328
+ "extern void _napi_register_xx_#{name}(void);"
329
+ end.join("\n")
330
+ addon_register_calls = node_api_addons.map(&:name).uniq.map do |name|
331
+ " _napi_register_xx_#{name}();"
332
+ end.join("\n")
333
+ bridge_setup = if node_api_addons.empty?
334
+ ''
335
+ else
336
+ <<~SETUP.chomp
337
+ #include <mutex>
338
+ #include <LynxWeakNodeAPI/primjs_weak_node_api_installer.h>
339
+ #include <PrimJS/primjs_weak_node_api_provider.h>
340
+
341
+ namespace {
342
+ extern "C" {
343
+ #{addon_register_declarations}
344
+ }
345
+
346
+ void LynxSetupWeakNodeAPI() {
347
+ static std::once_flag once;
348
+ std::call_once(once, []() {
349
+ PrimJSInstallWeakNodeApiRawPtrHostProvider(
350
+ PrimJSGetWeakNodeApiRawPtrHost);
351
+ SetupWeakNodeApiEnv();
352
+ #{addon_register_calls}
353
+ });
354
+ }
355
+ } // namespace
356
+ SETUP
357
+ end
358
+ setup_call = node_api_addons.empty? ? '' : ' LynxSetupWeakNodeAPI();'
359
+
360
+ <<~SOURCE
361
+ // Generated by cocoapods-lynx-library. Do not edit.
362
+ #{bridge_setup}
363
+
364
+ #{includes}
365
+
366
+ #ifdef __cplusplus
367
+ extern "C" {
368
+ #endif
369
+ void LynxGeneratedNodeAPIAddonUse(void) {
370
+ #{setup_call}
371
+ }
372
+ #ifdef __cplusplus
373
+ }
374
+ #endif
375
+ SOURCE
376
+ end
377
+
378
+ def podspec_source(node_api_addons = [])
379
+ addon_pod_names = node_api_addons.map(&:pod_name).uniq
380
+ addon_dependencies = addon_pod_names.map { |pod_name| " s.dependency '#{pod_name}'" }
381
+ .join("\n")
382
+ node_api_dependencies = if node_api_addons.empty?
383
+ []
384
+ else
385
+ [
386
+ 'LynxWeakNodeAPI/primjs_bridge',
387
+ 'PrimJS/napi/adapter'
388
+ ]
389
+ end
390
+ node_api_dependency_lines = node_api_dependencies.map do |pod_name|
391
+ " s.dependency '#{pod_name}'"
392
+ end.join("\n")
393
+ node_api_xcconfig = if node_api_addons.empty?
394
+ ''
395
+ else
396
+ [
397
+ ' s.pod_target_xcconfig = {',
398
+ ' \'HEADER_SEARCH_PATHS\' => \'$(inherited) "${PODS_ROOT}/LynxWeakNodeAPI/packages/weak-node-api/headers"\'',
399
+ ' }'
400
+ ].join("\n")
401
+ end
238
402
  <<~PODSPEC
239
403
  Pod::Spec.new do |s|
240
404
  s.name = 'LynxLibraryRegistry'
@@ -244,8 +408,11 @@ module Lynx
244
408
  s.license = 'Apache-2.0'
245
409
  s.author = 'Lynx'
246
410
  s.source = { :path => '.' }
247
- s.source_files = '#{REGISTRY_CLASS_NAME}.{h,m}'
411
+ s.source_files = '#{REGISTRY_CLASS_NAME}.{h,m}', '#{ADDON_USE_SOURCE_NAME}'
248
412
  s.dependency 'Lynx'
413
+ #{node_api_dependency_lines}
414
+ #{addon_dependencies}
415
+ #{node_api_xcconfig}
249
416
  s.requires_arc = true
250
417
  end
251
418
  PODSPEC
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-lynx-library
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.0.2.pre.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lynx Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-31 00:00:00.000000000 Z
11
+ date: 2026-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cocoapods
@@ -48,9 +48,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
48
48
  version: '0'
49
49
  required_rubygems_version: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - ">="
51
+ - - ">"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: 1.3.1
54
54
  requirements: []
55
55
  rubygems_version: 3.3.27
56
56
  signing_key: