1
+ # Copyright Google Inc. All Rights Reserved.
2
+ #
3
+ # Use of this source code is governed by an MIT-style license that can be
4
+ # found in the LICENSE file at https://angular.io/license
5
+
6
+ load ("@build_bazel_rules_typescript//internal:build_defs.bzl" , "tsc_wrapped_tsconfig" )
7
+
8
+ load (
9
+ "@build_bazel_rules_typescript//internal:common/compilation.bzl" ,
10
+ "COMMON_ATTRIBUTES" , "compile_ts" , "ts_providers_dict_to_struct"
11
+ )
12
+
13
+ load ("@build_bazel_rules_typescript//internal:common/json_marshal.bzl" , "json_marshal" )
14
+
15
+ # Calculate the expected output of the template compiler for every source in
16
+ # in the library. Most of these will be produced as empty files but it is
17
+ # unknown, without parsing, which will be empty.
18
+ def _expected_outs (ctx ):
19
+ result = []
20
+
21
+ for src in ctx .files .srcs :
22
+ if src .short_path .endswith (".ts" ):
23
+ basename = src .short_path [len (ctx .label .package ) + 1 :- 3 ]
24
+ result += [ctx .new_file (ctx .bin_dir , basename + ext ) for ext in [
25
+ ".ngfactory.js" ,
26
+ ".ngfactory.d.ts" ,
27
+ ".ngsummary.js" ,
28
+ ".ngsummary.d.ts" ,
29
+ ".ngsummary.json" ,
30
+ ]]
31
+ elif src .short_path .endswith (".css" ):
32
+ basename = src .short_path [len (ctx .label .package ) + 1 :- 4 ]
33
+ result += [ctx .new_file (ctx .bin_dir , basename + ext ) for ext in [
34
+ ".css.shim.ngstyle.js" ,
35
+ ".css.shim.ngstyle.d.ts" ,
36
+ ".css.ngstyle.js" ,
37
+ ".css.ngstyle.d.ts" ,
38
+ ]]
39
+ return result
40
+
41
+ def _ngc_tsconfig (ctx , files , srcs , ** kwargs ):
42
+ return dict (tsc_wrapped_tsconfig (ctx , files , srcs , ** kwargs ), ** {
43
+ "angularCompilerOptions" : {
44
+ "expectedOut" : [o .path for o in _expected_outs (ctx )],
45
+ }
46
+ })
47
+
48
+ def _compile_action (ctx , inputs , outputs , config_file_path ):
49
+ externs_files = []
50
+ non_externs_files = []
51
+ for output in outputs :
52
+ if output .basename .endswith (".es5.MF" ):
53
+ ctx .file_action (output , content = "" )
54
+ else :
55
+ non_externs_files .append (output )
56
+
57
+ # TODO(alexeagle): For now we mock creation of externs files
58
+ for externs_file in externs_files :
59
+ ctx .file_action (output = externs_file , content = "" )
60
+
61
+ action_inputs = inputs
62
+ if hasattr (ctx .attr , "node_modules" ):
63
+ action_inputs += [f for f in ctx .files .node_modules
64
+ if f .path .endswith (".ts" ) or f .path .endswith (".json" )]
65
+ if ctx .file .tsconfig :
66
+ action_inputs += [ctx .file .tsconfig ]
67
+
68
+ # One at-sign makes this a params-file, enabling the worker strategy.
69
+ # Two at-signs escapes the argument so it's passed through to ngc
70
+ # rather than the contents getting expanded.
71
+ if ctx .attr .supports_workers :
72
+ arguments = ["@@" + config_file_path ]
73
+ else :
74
+ arguments = ["-p" , config_file_path ]
75
+
76
+ ctx .action (
77
+ progress_message = "Compiling Angular templates (ngc) %s" % ctx .label ,
78
+ mnemonic = "AngularTemplateCompile" ,
79
+ inputs = action_inputs ,
80
+ outputs = non_externs_files ,
81
+ arguments = arguments ,
82
+ executable = ctx .executable .compiler ,
83
+ execution_requirements = {
84
+ "supports-workers" : str (int (ctx .attr .supports_workers )),
85
+ },
86
+ )
87
+
88
+ def _devmode_compile_action (ctx , inputs , outputs , config_file_path ):
89
+ # TODO(alexeagle): compile for feeding to Closure Compiler
90
+ _compile_action (ctx , inputs , outputs + _expected_outs (ctx ), config_file_path )
91
+
92
+ def _compile_ng (ctx ):
93
+ declarations = []
94
+ for dep in ctx .attr .deps :
95
+ if hasattr (dep , "typescript" ):
96
+ declarations += dep .typescript .transitive_declarations
97
+
98
+ tsconfig_json = ctx .new_file (ctx .label .name + "_tsconfig.json" )
99
+ ctx .file_action (output = tsconfig_json , content = json_marshal (
100
+ _ngc_tsconfig (ctx , ctx .files .srcs + declarations , ctx .files .srcs )))
101
+
102
+ _devmode_compile_action (ctx , ctx .files .srcs + declarations + [tsconfig_json ], [], tsconfig_json .path )
103
+
104
+ return {
105
+ "files" : depset (_expected_outs (ctx )),
106
+ "typescript" : {
107
+ # FIXME: expose the right outputs so this looks like a ts_library
108
+ "declarations" : [],
109
+ "transitive_declarations" : [],
110
+ "type_blacklisted_declarations" : [],
111
+ },
112
+ }
113
+
114
+ def _ng_module_impl (ctx ):
115
+ if ctx .attr .write_ng_outputs_only :
116
+ ts_providers = _compile_ng (ctx )
117
+ else :
118
+ ts_providers = compile_ts (ctx , is_library = True ,
119
+ compile_action = _compile_action ,
120
+ devmode_compile_action = _devmode_compile_action ,
121
+ tsc_wrapped_tsconfig = _ngc_tsconfig )
122
+
123
+ addl_declarations = [o for o in _expected_outs (ctx ) if o .path .endswith (".d.ts" )]
124
+ ts_providers ["typescript" ]["declarations" ] += addl_declarations
125
+ ts_providers ["typescript" ]["transitive_declarations" ] += addl_declarations
126
+
127
+ return ts_providers_dict_to_struct (ts_providers )
128
+
129
+
130
+ ng_module = rule (
131
+ implementation = _ng_module_impl ,
132
+ attrs = dict (COMMON_ATTRIBUTES , ** {
133
+ "srcs" : attr .label_list (allow_files = True ),
134
+
135
+ # To be used only to bootstrap @angular/core compilation,
136
+ # since we want to compile @angular/core with ngc, but ngc depends on
137
+ # @angular/core typescript output.
138
+ "write_ng_outputs_only" : attr .bool (default = False ),
139
+ "tsconfig" : attr .label (allow_files = True , single_file = True ),
140
+ "no_i18n" : attr .bool (default = False ),
141
+ # TODO(alexeagle): enable workers for ngc
142
+ "supports_workers" : attr .bool (default = False ),
143
+ "compiler" : attr .label (
144
+ default = Label ("//internal/ngc" ),
145
+ executable = True ,
146
+ cfg = "host" ,
147
+ ),
148
+ # @// is special syntax for the "main" repository
149
+ # The default assumes the user specified a target "node_modules" in their
150
+ # root BUILD file.
151
+ "node_modules" : attr .label (
152
+ default = Label ("@//:node_modules" )
153
+ ),
154
+ }),
155
+ )
0 commit comments