@@ -175,75 +175,38 @@ class ReactPlugin : Plugin<Project> {
175175 localExtension.jsRootDir.convention(localExtension.root)
176176 }
177177
178- // We create the task to produce schema from JS files.
179- val generateCodegenSchemaTask =
180- project.tasks.register(
181- " generateCodegenSchemaFromJavaScript" ,
182- GenerateCodegenSchemaTask ::class .java,
183- ) { it ->
184- it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
185- it.codegenDir.set(rootExtension.codegenDir)
186- it.generatedSrcDir.set(generatedSrcDir)
187- it.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
188-
189- // We're reading the package.json at configuration time to properly feed
190- // the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the
191- // parsePackageJson should be invoked inside this lambda.
192- val packageJson = findPackageJsonFile(project, rootExtension.root)
193- val parsedPackageJson = packageJson?.let { JsonUtils .fromPackageJson(it) }
194-
195- val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
196- val includesGeneratedCode =
197- parsedPackageJson?.codegenConfig?.includesGeneratedCode ? : false
198- if (jsSrcsDirInPackageJson != null ) {
199- it.jsRootDir.set(File (packageJson.parentFile, jsSrcsDirInPackageJson))
200- } else {
201- it.jsRootDir.set(localExtension.jsRootDir)
202- }
203- it.jsInputFiles.set(
204- project.fileTree(it.jsRootDir) { tree ->
205- tree.include(" **/*.js" )
206- tree.include(" **/*.jsx" )
207- tree.include(" **/*.ts" )
208- tree.include(" **/*.tsx" )
178+ // We're reading the package.json at configuration time to properly feed
179+ // the `jsRootDir` @Input property of the schema task & the onlyIf for both codegen tasks.
180+ val packageJson = findPackageJsonFile(project, rootExtension.root)
181+ val parsedPackageJson = packageJson?.let { JsonUtils .fromPackageJson(it) }
209182
210- tree.exclude(" node_modules/**/*" )
211- tree.exclude(" **/*.d.ts" )
212- // We want to exclude the build directory, to don't pick them up for execution
213- // avoidance.
214- tree.exclude(" **/build/**/*" )
215- }
216- )
217-
218- val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
219- it.onlyIf { (isLibrary || needsCodegenFromPackageJson) && ! includesGeneratedCode }
220- }
183+ val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
184+ val includesGeneratedCode = parsedPackageJson?.codegenConfig?.includesGeneratedCode ? : false
185+ val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
186+ val shouldRunCodegen = { (isLibrary || needsCodegenFromPackageJson) && ! includesGeneratedCode }
221187
222- // We create the task to generate Java code from schema.
188+ // We create the tasks to produce schema from JS files and generate artifacts from schema.
223189 val generateCodegenArtifactsTask =
224- project.tasks.register(
225- " generateCodegenArtifactsFromSchema" ,
226- GenerateCodegenArtifactsTask ::class .java,
227- ) { task ->
228- task.dependsOn(generateCodegenSchemaTask)
229- task.reactNativeDir.set(rootExtension.reactNativeDir)
230- task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
231- task.generatedSrcDir.set(generatedSrcDir)
232- task.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root))
233- task.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
234- task.libraryName.set(localExtension.libraryName)
235- task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
236-
237- // Please note that appNeedsCodegen is triggering a read of the package.json at
238- // configuration time as we need to feed the onlyIf condition of this task.
239- // Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
240- val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
241- val packageJson = findPackageJsonFile(project, rootExtension.root)
242- val parsedPackageJson = packageJson?.let { JsonUtils .fromPackageJson(it) }
243- val includesGeneratedCode =
244- parsedPackageJson?.codegenConfig?.includesGeneratedCode ? : false
245- task.onlyIf { (isLibrary || needsCodegenFromPackageJson) && ! includesGeneratedCode }
246- }
190+ registerCodegenTasks(
191+ project = project,
192+ rootExtension = rootExtension,
193+ generatedSrcDir = generatedSrcDir,
194+ packageJsonFile = packageJson,
195+ schemaTaskName = " generateCodegenSchemaFromJavaScript" ,
196+ artifactsTaskName = " generateCodegenArtifactsFromSchema" ,
197+ configureJsRoot = { task ->
198+ if (jsSrcsDirInPackageJson != null ) {
199+ task.jsRootDir.set(File (packageJson.parentFile, jsSrcsDirInPackageJson))
200+ } else {
201+ task.jsRootDir.set(localExtension.jsRootDir)
202+ }
203+ },
204+ configureCodegenArtifacts = { task ->
205+ task.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
206+ task.libraryName.set(localExtension.libraryName)
207+ },
208+ onlyIf = shouldRunCodegen,
209+ )
247210
248211 // We update the android configuration to include the generated sources.
249212 // This equivalent to this DSL:
@@ -266,6 +229,68 @@ class ReactPlugin : Plugin<Project> {
266229 project.tasks.named(" preBuild" , Task ::class .java).dependsOn(generateCodegenArtifactsTask)
267230 }
268231
232+ private fun registerCodegenTasks (
233+ project : Project ,
234+ rootExtension : PrivateReactExtension ,
235+ generatedSrcDir : Provider <Directory >,
236+ packageJsonFile : File ? ,
237+ schemaTaskName : String ,
238+ artifactsTaskName : String ,
239+ configureJsRoot : (GenerateCodegenSchemaTask ) -> Unit ,
240+ configureCodegenArtifacts : (GenerateCodegenArtifactsTask ) -> Unit ,
241+ onlyIf : () -> Boolean = { true },
242+ ): TaskProvider <GenerateCodegenArtifactsTask > {
243+ // We create the task to produce schema from JS files.
244+ val generateCodegenSchemaTask =
245+ project.tasks.register(
246+ schemaTaskName,
247+ GenerateCodegenSchemaTask ::class .java,
248+ ) { task ->
249+ task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
250+ task.codegenDir.set(rootExtension.codegenDir)
251+ task.generatedSrcDir.set(generatedSrcDir)
252+ task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
253+
254+ configureJsRoot(task)
255+
256+ task.jsInputFiles.set(
257+ project.fileTree(task.jsRootDir) { tree ->
258+ tree.include(" **/*.js" )
259+ tree.include(" **/*.jsx" )
260+ tree.include(" **/*.ts" )
261+ tree.include(" **/*.tsx" )
262+
263+ tree.exclude(" node_modules/**/*" )
264+ tree.exclude(" **/*.d.ts" )
265+ // We want to exclude the build directory, to don't pick them up for execution
266+ // avoidance.
267+ tree.exclude(" **/build/**/*" )
268+ }
269+ )
270+ task.onlyIf { onlyIf() }
271+ }
272+
273+ // We create the task to generate Java code from schema.
274+ return project.tasks.register(
275+ artifactsTaskName,
276+ GenerateCodegenArtifactsTask ::class .java,
277+ ) { task ->
278+ task.dependsOn(generateCodegenSchemaTask)
279+ task.reactNativeDir.set(rootExtension.reactNativeDir)
280+ task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
281+ task.generatedSrcDir.set(generatedSrcDir)
282+ task.packageJsonFile.set(packageJsonFile)
283+ task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
284+
285+ configureCodegenArtifacts(task)
286+
287+ // The caller decides whether codegen should run. For app/library projects this depends on
288+ // package.json and includesGeneratedCode. Pure C++ dependencies are filtered before task
289+ // registration, so their generated tasks can always run.
290+ task.onlyIf { onlyIf() }
291+ }
292+ }
293+
269294 /* * This function sets up Autolinking for App users */
270295 private fun configureAutolinking (
271296 project : Project ,
@@ -293,18 +318,6 @@ class ReactPlugin : Plugin<Project> {
293318 generatedPureCxxSourceDir,
294319 pureCxxDependencies,
295320 )
296- val pureCxxCmakeListsPaths =
297- pureCxxDependencies
298- .mapNotNull { dependency ->
299- val libraryName = dependency.platforms?.android?.libraryName ? : return @mapNotNull null
300- libraryName to
301- generatedPureCxxSourceDir
302- .get()
303- .file(" $libraryName /jni/CMakeLists.txt" )
304- .asFile
305- .absolutePath
306- }
307- .toMap()
308321
309322 // We add a task called generateAutolinkingPackageList to do not clash with the existing task
310323 // called generatePackageList. This can to be renamed once we unlink the rn <-> cli
@@ -338,7 +351,11 @@ class ReactPlugin : Plugin<Project> {
338351 ) { task ->
339352 task.autolinkInputFile.set(rootGeneratedAutolinkingFile)
340353 task.generatedOutputDirectory.set(generatedAutolinkingJniDir)
341- task.generatedPureCxxCmakeListsPaths.set(pureCxxCmakeListsPaths)
354+
355+ if (pureCxxDependencies.isNotEmpty()) {
356+ task.generatedPureCxxSourceDirectory.set(generatedPureCxxSourceDir)
357+ }
358+
342359 task.dependsOn(pureCxxCodegenTasks)
343360 }
344361 project.tasks
@@ -370,61 +387,42 @@ class ReactPlugin : Plugin<Project> {
370387 generatedPureCxxSourceDir : Provider <Directory >,
371388 dependencies : List <ModelAutolinkingDependenciesJson >,
372389 ): List <TaskProvider <GenerateCodegenArtifactsTask >> {
373- return dependencies.map { dependency ->
374- val android = dependency.platforms?.android!!
375- val libraryName = android.libraryName!!
390+ // Pure C++ dependencies are not included as Gradle subprojects, so configureCodegen won't run
391+ // for them. The app owns these generated codegen artifacts and links them from autolinking.
392+ return dependencies.mapNotNull { dependency ->
393+ val android = dependency.platforms?.android ? : return @mapNotNull null
394+ val libraryName = android.libraryName ? : return @mapNotNull null
376395 val dependencyRoot = File (dependency.root)
377396 val packageJson = File (dependencyRoot, " package.json" )
378397 val parsedPackageJson = JsonUtils .fromPackageJson(packageJson)
379398 val jsSrcsDir = parsedPackageJson?.codegenConfig?.jsSrcsDir
380399 val generatedSrcDir = generatedPureCxxSourceDir.map { it.dir(libraryName) }
381400 val taskNameSuffix = taskNameSuffixForDependency(dependency)
382- val generateCodegenSchemaTask =
383- project.tasks.register (
384- " generate ${taskNameSuffix} CodegenSchemaFromJavaScript " ,
385- GenerateCodegenSchemaTask :: class .java ,
386- ) { task ->
387- task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
388- task.codegenDir.set(rootExtension.codegenDir)
389- task.generatedSrcDir.set(generatedSrcDir)
390- task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
401+
402+ registerCodegenTasks (
403+ project = project ,
404+ rootExtension = rootExtension ,
405+ generatedSrcDir = generatedSrcDir,
406+ packageJsonFile = packageJson,
407+ schemaTaskName = " generate ${taskNameSuffix} CodegenSchemaFromJavaScript " ,
408+ artifactsTaskName = " generate ${taskNameSuffix} CodegenArtifactsFromSchema " ,
409+ configureJsRoot = { task ->
391410 if (jsSrcsDir != null ) {
392411 task.jsRootDir.set(File (packageJson.parentFile, jsSrcsDir))
393412 } else {
394413 task.jsRootDir.set(dependencyRoot)
395414 }
396- task.jsInputFiles.set(
397- project.fileTree(task.jsRootDir) { tree ->
398- tree.include(" **/*.js" )
399- tree.include(" **/*.jsx" )
400- tree.include(" **/*.ts" )
401- tree.include(" **/*.tsx" )
402-
403- tree.exclude(" node_modules/**/*" )
404- tree.exclude(" **/*.d.ts" )
405- tree.exclude(" **/build/**/*" )
406- }
407- )
408- }
409-
410- project.tasks.register(
411- " generate${taskNameSuffix} CodegenArtifactsFromSchema" ,
412- GenerateCodegenArtifactsTask ::class .java,
413- ) { task ->
414- task.dependsOn(generateCodegenSchemaTask)
415- task.reactNativeDir.set(rootExtension.reactNativeDir)
416- task.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
417- task.generatedSrcDir.set(generatedSrcDir)
418- task.packageJsonFile.set(packageJson)
419- val codegenJavaPackageName = parsedPackageJson?.codegenConfig?.android?.javaPackageName
420- if (codegenJavaPackageName != null ) {
421- task.codegenJavaPackageName.set(codegenJavaPackageName)
422- } else {
423- task.codegenJavaPackageName.set(extension.codegenJavaPackageName)
424- }
425- task.libraryName.set(libraryName)
426- task.nodeWorkingDir.set(project.layout.projectDirectory.asFile.absolutePath)
427- }
415+ },
416+ configureCodegenArtifacts = { task ->
417+ val codegenJavaPackageName = parsedPackageJson?.codegenConfig?.android?.javaPackageName
418+ if (codegenJavaPackageName != null ) {
419+ task.codegenJavaPackageName.set(codegenJavaPackageName)
420+ } else {
421+ task.codegenJavaPackageName.set(extension.codegenJavaPackageName)
422+ }
423+ task.libraryName.set(libraryName)
424+ },
425+ )
428426 }
429427 }
430428
@@ -449,8 +447,8 @@ class ReactPlugin : Plugin<Project> {
449447 }
450448
451449 private fun taskNameSuffixForDependency (dependency : ModelAutolinkingDependenciesJson ): String =
452- dependency.nameCleansed
453- .split( Regex ( " [^A-Za-z0-9]+ " ))
454- .filter { it.isNotEmpty() }
455- .joinToString( " " ) { it. replaceFirstChar { char -> char.titlecase() } }
450+ dependency.name
451+ .map { char -> if (char.isLetterOrDigit()) char.toString() else " _ ${char.code} _ " }
452+ .joinToString( " " )
453+ .replaceFirstChar { char -> char.titlecase() }
456454}
0 commit comments