feat(domain): naming template engine (Jinja safe subset, MP variables, path layout)

- naming/engine: lexer/parser/AST/render for {{ }} / if-elif-else / whitelisted filters
  (default pad pad2 upper lower trim replace truncate date join); rejects for/set/attribute/
  subscript/call/~/% with line:col errors and 'did you mean' hints
- naming/variables: variable table aligned with MoviePilot names plus ours (cut, airDate,
  issue, slotName, libraryRoot ...); buildNamingVars from parsed release + entity + units
- naming/layout: split by literal '/', segment roles (category/root/season/sub/file),
  value escaping, reserved names, 255-byte segments, validateNamingTemplate
- naming/defaults: MP default movie/tv + our variety template, v1 syntax upgrade,
  entity > root > global override resolution, builtin preview samples
- path/binding: resolveTargetDirectory keeps bound dirs, only unbound segments render;
  renderMediaFileName = last segment of the full template; DEFAULT_TEMPLATES = MP v2
- differential: 34 cases vs MP (21 identical, 13 documented deviations)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 15:24:32 +08:00
1 parent e8745115f4
commit f7c75ad781
22 files changed
+2674 -281

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
// 命名模板引擎(docs/design/naming-template.md):Jinja 安全子集 + MP 变量 + 段角色/清理 + 覆盖层级
export {
LEGACY_NAMING_VERSION,
LEGACY_V1_NAMING,
LEGACY_V1_TEMPLATES,
type LegacyNamingTemplateSet,
MP_DEFAULT_NAMING,
NAMING_SAMPLES,
type NamingOverride,
type NamingSample,
type NamingSource,
type NamingTemplates,
namingCanonicalJson,
namingKindOf,
resolveNamingTemplates,
upgradeLegacyTemplate,
upgradeLegacyTemplateSet,
} from "./defaults.ts";
export {
type CompiledNaming,
type CompileOptions,
compileNaming,
endsWithFileExt,
NAMING_FILTERS,
NAMING_LIMITS,
type NamingIssue,
NamingTemplateError,
type NamingValue,
type NamingVars,
renderNamingPieces,
renderNamingString,
tryCompileNaming,
unguardedOutputs,
} from "./engine.ts";
export {
type NamingPathResult,
type NamingSegment,
type NamingValidation,
PATH_MAX_BYTES,
type RenderPathOptions,
renderNamingPath,
SEGMENT_MAX_BYTES,
type SegmentRole,
validateNamingTemplate,
} from "./layout.ts";
export {
buildNamingVars,
exampleVars,
NAMING_VARIABLE_NAMES,
NAMING_VARIABLES,
type NamingEntityInput,
type NamingKind,
type NamingVarGroup,
type NamingVariableDef,
normalizeExt,
SEASON_VARS,
TITLE_VARS,
} from "./variables.ts";