# encoding: utf-8 # frozen_string_literal: true require "open-uri" module Brandish module Processors module All # "Imports" another file into this current file. This takes the file, # parses it, and inserts it directly into the position that the import # was placed. By default, this forces the file to be in the source # directory, doing some awkward joining to make it work. This takes # one pair - `"name"`, `"link"`, or `"file"` - which contains the name of # the file to import. It takes two options: `:absolute_allowed`, which # allows imports to be outside of the source directory; and # `:remote_allowed`, which allows remote files to be imported, using any # of the protocols supported by open-uri. # # For local file imports, if no extensions were provided, an extension # of `.br` is automatically added. For remote files, extensions are # always required. # # Imports are handled as if the entire imported file was copy and pasted # into the source document. # # Options: # # - `:absolute_allowed` - Optional. Despite its name, if this value is # `true`, imports can be used with any file that is outside of the # source directory. Otherwise, the files will be forced to be inside # the source directory, as if the source directory is the root of the # file system. # - `:remote_allowed` - Optional. Whether remote imports should be # allowed. # # Pairs: # # - `"src"`, `"file"`, `"name"`, or `"link"` - Required. These all do the # same thing - it provides the name of the file to import. # # @example local file # # @example remote file # # @example absolute local file # # @note # Be careful when using `:remote_allowed` - this can cause possible # security issues if the remote is not trusted. class Import < Processor::Base include Processor::Command register %i(all import) => self pairs :src, :file, :name, :link # Accepts the root node of the parsed file, processing the result as # if it were an extension of the original source tree. # # @return [Parser::Node] def perform accept(parse_file) end private def load_file file = @pairs["src"] || @pairs["file"] || @pairs["name"] || @pairs["link"] return file if file fail PairError.new("Expected one of src, file, name, or link, " \ "got nothing", @node.location) end def parse_file load_file =~ /\A(https?|ftp):/ ? parse_remote_file : parse_local_file end def parse_remote_file fail_remote_file unless @options[:remote_allowed] open(load_file) { |io| @context.configure.parse_from(io, file) } end def fail_remote_file fail PairError.new("Remote file given, but not supported", @node.location) end def parse_local_file file = ::Pathname.new(load_file) file = file.sub_ext(".br") unless load_file =~ /\.(.+?)\z/ path = @context.configure.sources.find(file) @context.configure.roots[path] end end end end end