 		raw: raw
 		lines: lines
 		commentLines: commentLines
+
+# } Get the type and name of this package (if any).
+packageInformation = {}
+packageLookup = {}
+for filename, {commentLines} of sources
+	
+	packageTypeAndName = ///
+
+^(?:
+	(server)\/packages\/([^/]+)/index
+	|
+	(client)\/modules\/packages\/([^/]+)/index
+)
+
+///
+		
+	continue unless (matches = filename.match packageTypeAndName)?
+	
+	type = matches[1] ? matches[3]
+	name = matches[2] ? matches[4]
+	
+	packageInformation[type] ?= {}
+	packageLookup[filename] = name: name, type: type
+	
+	# } Only do this once for each package.
+	continue if packageInformation[type][name]?
+	
+	packageInformation[type][name] = filename: filename
 	
 # Generate hook documentation.
 generateHookDocumentation = do ->

					description: description
					name: hookName
	
	# } Output the hook information.			
	alphabetical = Object.keys(hookInformation).sort()
	for filename in alphabetical
		hooks = hookInformation[filename]
		
		# } Top-level list: filenames
		markdown += "* ##[#{

		
		# Your code goes here...

The list below was dynamically generated from the source code. There is a
description and a list of implementing packages for each hook.

---

"""
	
	packagesImplementingHook = (hookName) ->
	
		implementsPattern = new RegExp "^\#\\s(\#\# )?Implements hook `#{
			hookName
		}`"
			
		packages = []
		
		for filename, {commentLines} of sources
			continue unless (package_ = packageLookup[filename])?
			
			packages.push package_ if commentLines.some (line) ->
				line.match implementsPattern
					
		packages
	
	hookInformation = {}
	for filename, {commentLines} of sources
