feat(skd): support @file references for query text in skd-compile and skd-edit

Allows using "@path/to/file.sql" instead of inline query text.
Path resolved relative to definition file, then CWD; absolute paths supported.

Closes #9

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-03-17 20:06:02 +03:00
co-authored by Claude Opus 4.6
parent ffa3189442
commit 05fc7eba27
8 changed files with 133 additions and 11 deletions
@@ -1,4 +1,4 @@
# skd-compile v1.0 — Compile 1C DCS from JSON
# skd-compile v1.1 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$DefinitionFile,
@@ -41,6 +41,9 @@ if (-not $def.dataSets -or $def.dataSets.Count -eq 0) {
exit 1
}
# Base directory for resolving @file references in query
$script:queryBaseDir = if ($DefinitionFile) { [System.IO.Path]::GetDirectoryName($DefinitionFile) } else { (Get-Location).Path }
# --- 2. XML helpers ---
$script:xml = New-Object System.Text.StringBuilder 16384
@@ -55,6 +58,27 @@ function Esc-Xml {
return $s.Replace('&','&amp;').Replace('<','&lt;').Replace('>','&gt;').Replace('"','&quot;')
}
function Resolve-QueryValue {
param([string]$val, [string]$baseDir)
if (-not $val.StartsWith("@")) { return $val }
$filePath = $val.Substring(1)
if ([System.IO.Path]::IsPathRooted($filePath)) {
$candidates = @($filePath)
} else {
$candidates = @(
(Join-Path $baseDir $filePath),
(Join-Path (Get-Location).Path $filePath)
)
}
foreach ($c in $candidates) {
if (Test-Path $c) {
return (Get-Content -Raw -Encoding UTF8 $c).TrimEnd()
}
}
Write-Error "Query file not found: $filePath (searched: $($candidates -join ', '))"
exit 1
}
function Emit-MLText {
param([string]$tag, [string]$text, [string]$indent)
X "$indent<$tag xsi:type=`"v8:LocalStringType`">"
@@ -672,7 +696,8 @@ function Emit-DataSet {
# Type-specific content
if ($dsType -eq "DataSetQuery") {
X "$indent`t<query>$(Esc-Xml "$($ds.query)")</query>"
$queryText = Resolve-QueryValue "$($ds.query)" $script:queryBaseDir
X "$indent`t<query>$(Esc-Xml $queryText)</query>"
if ($ds.autoFillFields -eq $false) {
X "$indent`t<autoFillFields>false</autoFillFields>"
}
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# skd-compile v1.0 — Compile 1C DCS from JSON
# skd-compile v1.1 — Compile 1C DCS from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import json
@@ -13,6 +13,25 @@ def esc_xml(s):
return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
def resolve_query_value(val, base_dir):
if not val.startswith("@"):
return val
file_path = val[1:]
if os.path.isabs(file_path):
candidates = [file_path]
else:
candidates = [
os.path.join(base_dir, file_path),
os.path.join(os.getcwd(), file_path),
]
for c in candidates:
if os.path.exists(c):
with open(c, 'r', encoding='utf-8-sig') as f:
return f.read().rstrip()
print(f"Query file not found: {file_path} (searched: {', '.join(candidates)})", file=sys.stderr)
sys.exit(1)
def emit_mltext(lines, indent, tag, text):
if not text:
lines.append(f"{indent}<{tag}/>")
@@ -530,7 +549,8 @@ def emit_data_set(lines, ds, indent, default_source):
# Type-specific content
if ds_type == 'DataSetQuery':
lines.append(f'{indent}\t<query>{esc_xml(str(ds.get("query", "")))}</query>')
query_text = resolve_query_value(str(ds.get("query", "")), query_base_dir)
lines.append(f'{indent}\t<query>{esc_xml(query_text)}</query>')
if ds.get('autoFillFields') is False:
lines.append(f'{indent}\t<autoFillFields>false</autoFillFields>')
elif ds_type == 'DataSetObject':
@@ -1351,6 +1371,10 @@ def main():
print("JSON must have at least one entry in 'dataSets'", file=sys.stderr)
sys.exit(1)
# Base directory for resolving @file references in query
global query_base_dir
query_base_dir = os.path.dirname(def_file) if args.DefinitionFile else os.getcwd()
# --- 2. Resolve defaults ---
# DataSources