Created
July 6, 2018 23:26
-
-
Save foca/c720318018f334cbe9dc7f3818d272eb to your computer and use it in GitHub Desktop.
Tiny script to build GNU Make dependency files for JS `import` rules or CSS `@import` rules.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# Generate make dependencies by parsing a tree of JS / CSS files. | |
# | |
# Usage | |
# ----- | |
# | |
# Add this to your Makefile: | |
# | |
# ``` | |
# .deps.js.mk: | |
# makedepend --js ./assets/js > $@ | |
# | |
# .deps.css.mk: | |
# makedepend --css ./assets/css > $@ | |
# | |
# -include .deps.js.mk .deps.css.mk | |
# ``` | |
# | |
# How it works | |
# ------------ | |
# | |
# ``` | |
# // foo.js | |
# import Bar from './bar.js' | |
# import './baz.js' | |
# import _ from 'lodash' | |
# <code> | |
# | |
# // bar.js | |
# import './baz.js' | |
# <code> | |
# | |
# // baz.js | |
# <code, but no imports> | |
# ``` | |
# | |
# It will generate the following output: | |
# | |
# ``` | |
# foo.js: bar.js baz.js | |
# @touch $@ | |
# | |
# bar.js: baz.js | |
# @touch $@ | |
# ``` | |
# | |
# You can see `baz` is not set as a rule -- only a dependency, since it doesn't | |
# depend on anything itself. Finally, `lodash` doesn't resolve to a file in our | |
# tree (it's most likely an npm dependency), so there's no need to have a rule | |
# for that. | |
require "pathname" | |
require "optparse" | |
Format = Struct.new(:desc, :glob, :scanner, :extractor) | |
types = { | |
js: Format.new( | |
"Scan for ES2016 `import` statements", | |
"**/*.js", /^\s*import/, /^.*["'](.+)["'].*$/ | |
), | |
css: Format.new( | |
"Scan for CSS `@import` statements", | |
"**/*.css", /^\s*@import/, /^.*["'](.+)["'].*$/ | |
) | |
} | |
type = nil | |
parser = OptionParser.new do |opts| | |
opts.banner = "Usage: #{$0} [--js|--css] <directory>" | |
types.each do |key, format| | |
opts.on("--#{key}", format.desc) do |set| | |
type = format if set | |
end | |
end | |
end | |
parser.parse! | |
puts Pathname.new(ARGV.fetch(0) { abort parser.banner }) | |
.glob(type.glob) | |
.each_with_object({}) { |file, deps| | |
deps[file] = file.each_line | |
.grep(type.scanner) | |
.map { |import| file.dirname + import.sub(type.extractor, '\1').chomp } | |
.select { |import| import.file? } | |
} | |
.select { |_, deps| deps.any? } | |
.map { |file, deps| format("%s: %s\n\t@touch $@", file, deps.join(" ")) } | |
.join("\n\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment