99 lines
3.5 KiB
Ruby
Executable File
99 lines
3.5 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
||
# frozen_string_literal: true
|
||
|
||
require "json"
|
||
require "optparse"
|
||
require "time"
|
||
require_relative "schema"
|
||
|
||
ENV["TZ"] = "Europe/Paris"
|
||
ROOT = File.expand_path("..", __dir__)
|
||
CONTENT = File.join(ROOT, "src", "content")
|
||
|
||
options = {}
|
||
parser = OptionParser.new do |opts|
|
||
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} SECTION IDENTIFIANT [options]"
|
||
opts.on("--nature NATURE", "nature d’une fiche de vocabulaire") { |value| options[:nature] = value }
|
||
opts.on("--title TITRE", "titre initial") { |value| options[:title] = value }
|
||
end
|
||
|
||
begin
|
||
parser.parse!
|
||
raise "SECTION et IDENTIFIANT sont requis, sans argument supplémentaire" unless ARGV.length == 2
|
||
section_name, identifier = ARGV
|
||
|
||
section = SECTION_ALIASES[section_name]
|
||
raise "section inconnue : #{section_name}" unless section
|
||
|
||
normalize = ->(value) { value.strip.unicode_normalize(:nfc) }
|
||
identifier = normalize.call(identifier)
|
||
|
||
if section == "signes"
|
||
match = identifier.match(/\A(?:mzl-)?([0-9]{1,3})\z/)
|
||
raise "le numéro MZL doit être compris entre 1 et 999" unless match && match[1].to_i.between?(1, 999)
|
||
mzl = format("%03d", match[1].to_i)
|
||
filename = "mzl-#{mzl}"
|
||
else
|
||
leading_hyphen = identifier.start_with?("-")
|
||
body = leading_hyphen ? identifier[1..] : identifier
|
||
raise "seul le vocabulaire accepte un identifiant commençant par un tiret" if leading_hyphen && section != "vocabulaire"
|
||
valid = body && !body.empty? && identifier != "_index" && identifier == identifier.downcase &&
|
||
!identifier.end_with?("-") && !identifier.include?("--") && body.match?(/\A[\p{Alnum}-]+\z/u)
|
||
raise "identifiant de fichier invalide" unless valid
|
||
filename = identifier
|
||
end
|
||
|
||
nature = options[:nature]&.unicode_normalize(:nfc)
|
||
if section == "vocabulaire"
|
||
raise "--nature est requis pour le vocabulaire" unless nature
|
||
raise "nature grammaticale inconnue : #{nature}" unless VOCABULARY_FIELDS.key?(nature)
|
||
elsif nature
|
||
raise "--nature est réservé au vocabulaire"
|
||
end
|
||
|
||
title = if options[:title]
|
||
normalize.call(options[:title])
|
||
elsif section == "signes"
|
||
""
|
||
elsif section == "vocabulaire"
|
||
filename
|
||
else
|
||
filename.tr("-", " ").sub(/\A./) { |char| char.upcase }
|
||
end
|
||
|
||
tables = if section == "vocabulaire"
|
||
{
|
||
"extra" => VOCABULARY_FIELDS.fetch(nature).to_h { |field| [field, LIST_FIELDS.include?(field) ? [] : ""] },
|
||
"taxonomies" => { "natures" => [nature] }
|
||
}
|
||
else
|
||
SECTION_FIELDS.fetch(section).transform_values do |fields|
|
||
fields.to_h { |field| [field, LIST_FIELDS.include?(field) ? [] : ""] }
|
||
end
|
||
end
|
||
tables["extra"]["mzl"] = mzl if section == "signes"
|
||
|
||
lines = [
|
||
"+++",
|
||
"title = #{JSON.generate(title)}",
|
||
"date = #{Time.now.iso8601}",
|
||
"# updated = YYYY-MM-DDTHH:MM:SS+HH:MM",
|
||
'description = ""',
|
||
"draft = true"
|
||
]
|
||
|
||
tables.each do |table, fields|
|
||
lines << ""
|
||
lines << "[#{table}]"
|
||
fields.each { |field, value| lines << "#{field} = #{JSON.generate(value)}" }
|
||
end
|
||
lines += ["+++", ""]
|
||
|
||
destination = File.join(CONTENT, section, "#{filename}.md")
|
||
File.open(destination, File::WRONLY | File::CREAT | File::EXCL, 0o644) { |file| file.write(lines.join("\n")) }
|
||
puts "Brouillon créé : #{destination.delete_prefix(ROOT + '/')}"
|
||
rescue OptionParser::ParseError, RuntimeError, Errno::EEXIST, SystemCallError => e
|
||
warn "Erreur : #{e.message}"
|
||
exit 1
|
||
end
|