@@ -7,7 +7,6 @@ to the `deps` of one of their targets.
77"""
88
99load ("//:providers.bzl" , "DeclarationInfo" , "JSNamedModuleInfo" , "LinkablePackageInfo" , "NodeContextInfo" )
10- load ("//internal/common:path_utils.bzl" , "strip_external" )
1110
1211_DOC = """The pkg_npm rule creates a directory containing a publishable npm artifact.
1312
@@ -68,14 +67,12 @@ $ bazel run @nodejs//:npm_node_repositories who
6867$ bazel run :my_package.publish
6968```
7069
71- > Note that the `.pack` and `.publish` commands require that the `bazel-out` symlink exists in your project.
72- > Also, you must run the command from the workspace root directory containing the `bazel-out` symlink.
73-
7470You can pass arguments to npm by escaping them from Bazel using a double-hyphen, for example:
7571
7672`bazel run my_package.publish -- --tag=next`
7773"""
7874
75+ # Used in angular/angular /packages/bazel/src/ng_package/ng_package.bzl
7976PKG_NPM_ATTRS = {
8077 "package_name" : attr .string (
8178 doc = """Optional package_name that this npm package may be imported as.""" ,
@@ -119,6 +116,11 @@ PKG_NPM_ATTRS = {
119116 doc = """Other targets which produce files that should be included in the package, such as `rollup_bundle`""" ,
120117 allow_files = True ,
121118 ),
119+ "_npm_script_generator" : attr .label (
120+ default = Label ("//internal/pkg_npm:npm_script_generator" ),
121+ cfg = "host" ,
122+ executable = True ,
123+ ),
122124 "_packager" : attr .label (
123125 default = Label ("//internal/pkg_npm:packager" ),
124126 cfg = "host" ,
@@ -130,6 +132,7 @@ PKG_NPM_ATTRS = {
130132 ),
131133}
132134
135+ # Used in angular/angular /packages/bazel/src/ng_package/ng_package.bzl
133136PKG_NPM_OUTPUTS = {
134137 "pack" : "%{name}.pack" ,
135138 "publish" : "%{name}.publish" ,
@@ -141,6 +144,7 @@ PKG_NPM_OUTPUTS = {
141144def _filter_out_external_files (ctx , files , package_path ):
142145 result = []
143146 for file in files :
147+ # NB: package_path may be an empty string
144148 if file .short_path .startswith (package_path ) and not file .short_path .startswith ("../" ):
145149 result .append (file .path )
146150 else :
@@ -149,16 +153,17 @@ def _filter_out_external_files(ctx, files, package_path):
149153 result .append (file .path )
150154 return result
151155
152- def create_package (ctx , deps_sources , nested_packages ):
156+ # Used in angular/angular /packages/bazel/src/ng_package/ng_package.bzl
157+ def create_package (ctx , deps_files , nested_packages ):
153158 """Creates an action that produces the npm package.
154159
155160 It copies srcs and deps into the artifact and produces the .pack and .publish
156161 scripts.
157162
158163 Args:
159164 ctx: the skylark rule context
160- deps_sources: Files which have been specified as dependencies. Usually ".js" or ".d.ts"
161- generated files.
165+ deps_files: list of files to include in the package which have been
166+ specified as dependencies
162167 nested_packages: list of TreeArtifact outputs from other actions which are
163168 to be nested inside this package
164169
@@ -167,14 +172,27 @@ def create_package(ctx, deps_sources, nested_packages):
167172 """
168173
169174 stamp = ctx .attr .node_context_data [NodeContextInfo ].stamp
175+
176+ all_files = deps_files + ctx .files .srcs
177+
178+ if not stamp and len (all_files ) == 1 and all_files [0 ].is_directory and len (ctx .files .nested_packages ) == 0 :
179+ # Special case where these is a single dep that is a directory artifact and there are no
180+ # source files or nested_packages; in that case we assume the package is contained within
181+ # that single directory and there is no work to do
182+ package_dir = all_files [0 ]
183+
184+ _create_npm_scripts (ctx , package_dir )
185+
186+ return package_dir
187+
170188 package_dir = ctx .actions .declare_directory (ctx .label .name )
171189 package_path = ctx .label .package
172190
173191 # List of dependency sources which are local to the package that defines the current
174192 # target. Also include files from external repositories that explicitly specified in
175193 # the vendor_external list. We only want to package deps files which are inside of the
176194 # current package unless explicitely specified.
177- filtered_deps_sources = _filter_out_external_files (ctx , deps_sources , package_path )
195+ filtered_deps_sources = _filter_out_external_files (ctx , deps_files , package_path )
178196
179197 args = ctx .actions .args ()
180198 args .use_param_file ("%s" , use_always = True )
@@ -186,17 +204,12 @@ def create_package(ctx, deps_sources, nested_packages):
186204 args .add_joined (filtered_deps_sources , join_with = "," , omit_if_empty = False )
187205 args .add_joined ([p .path for p in nested_packages ], join_with = "," , omit_if_empty = False )
188206 args .add (ctx .attr .substitutions )
189- args .add_all ([ctx .outputs .pack .path , ctx .outputs .publish .path ])
190207 args .add (ctx .attr .replace_with_version )
191208 args .add (ctx .version_file .path if stamp else "" )
192209 args .add_joined (ctx .attr .vendor_external , join_with = "," , omit_if_empty = False )
193210 args .add ("1" if ctx .attr .hide_build_files else "0" )
194211
195- # require.resolve expects the path to start with the workspace name and not "external"
196- run_npm_template_path = strip_external (ctx .file ._run_npm_template .path )
197- args .add (run_npm_template_path )
198-
199- inputs = ctx .files .srcs + deps_sources + nested_packages + [ctx .file ._run_npm_template ]
212+ inputs = ctx .files .srcs + deps_files + nested_packages
200213
201214 # The version_file is an undocumented attribute of the ctx that lets us read the volatile-status.txt file
202215 # produced by the --workspace_status_command. That command will be executed whenever
@@ -210,34 +223,60 @@ def create_package(ctx, deps_sources, nested_packages):
210223 mnemonic = "AssembleNpmPackage" ,
211224 executable = ctx .executable ._packager ,
212225 inputs = inputs ,
213- outputs = [package_dir , ctx . outputs . pack , ctx . outputs . publish ],
226+ outputs = [package_dir ],
214227 arguments = [args ],
215228 )
229+
230+ _create_npm_scripts (ctx , package_dir )
231+
216232 return package_dir
217233
234+ def _create_npm_scripts (ctx , package_dir ):
235+ args = ctx .actions .args ()
236+ args .add_all ([
237+ package_dir .path ,
238+ ctx .outputs .pack .path ,
239+ ctx .outputs .publish .path ,
240+ ctx .file ._run_npm_template .path ,
241+ ])
242+
243+ ctx .actions .run (
244+ progress_message = "Generating npm pack & publish scripts" ,
245+ mnemonic = "GenerateNpmScripts" ,
246+ executable = ctx .executable ._npm_script_generator ,
247+ inputs = [ctx .file ._run_npm_template , package_dir ],
248+ outputs = [ctx .outputs .pack , ctx .outputs .publish ],
249+ arguments = [args ],
250+ # Must be run local (no sandbox) so that the pwd is the actual execroot
251+ # in the script which is used to generate the path in the pack & publish
252+ # scripts.
253+ execution_requirements = {"local" : "1" },
254+ )
255+
218256def _pkg_npm (ctx ):
219- sources_depsets = []
257+ deps_files_depsets = []
220258
221259 for dep in ctx .attr .deps :
222260 # Collect whatever is in the "data"
223- sources_depsets .append (dep .data_runfiles .files )
261+ deps_files_depsets .append (dep .data_runfiles .files )
224262
225263 # Only collect DefaultInfo files (not transitive)
226- sources_depsets .append (dep .files )
264+ deps_files_depsets .append (dep .files )
227265
228266 # All direct & transitive JavaScript-producing deps
229267 # TODO: switch to JSModuleInfo when it is available
230268 if JSNamedModuleInfo in dep :
231- sources_depsets .append (dep [JSNamedModuleInfo ].sources )
269+ deps_files_depsets .append (dep [JSNamedModuleInfo ].sources )
232270
233271 # Include all transitive declerations
234272 if DeclarationInfo in dep :
235- sources_depsets .append (dep [DeclarationInfo ].transitive_declarations )
236-
237- sources = depset (transitive = sources_depsets )
273+ deps_files_depsets .append (dep [DeclarationInfo ].transitive_declarations )
238274
239275 # Note: to_list() should be called once per rule!
240- package_dir = create_package (ctx , sources .to_list (), ctx .files .nested_packages )
276+ deps_files = depset (transitive = deps_files_depsets ).to_list ()
277+
278+ package_dir = create_package (ctx , deps_files , ctx .files .nested_packages )
279+
241280 package_dir_depset = depset ([package_dir ])
242281
243282 result = [
0 commit comments