feat(rust): add --scene-info-json parameter for LLM extraction results
- Add SceneInfoJson struct with serde rename for camelCase compatibility - Add ApiEndpointJson and BusinessLogicJson support structs - Add scene_info_json field to GenerateSceneRequest (backward compatible) - Rename browser_script to browser_script_skeleton - Add new browser_script that delegates based on scene_info presence - Add browser_script_with_business_logic for enhanced script generation - Update CLI to accept --scene-info-json parameter - Update usage string to document new parameter Generated with [Qoder][https://qoder.com]
This commit is contained in:
@@ -2,7 +2,7 @@ use std::env;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use sgclaw::generated_scene::analyzer::SceneKind;
|
use sgclaw::generated_scene::analyzer::SceneKind;
|
||||||
use sgclaw::generated_scene::generator::{generate_scene_package, GenerateSceneRequest};
|
use sgclaw::generated_scene::generator::{generate_scene_package, GenerateSceneRequest, SceneInfoJson};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Err(err) = run() {
|
if let Err(err) = run() {
|
||||||
@@ -13,6 +13,10 @@ fn main() {
|
|||||||
|
|
||||||
fn run() -> Result<(), String> {
|
fn run() -> Result<(), String> {
|
||||||
let args = parse_args(env::args().skip(1))?;
|
let args = parse_args(env::args().skip(1))?;
|
||||||
|
let scene_info: Option<SceneInfoJson> = args.scene_info_json
|
||||||
|
.map(|json| serde_json::from_str(&json))
|
||||||
|
.transpose()
|
||||||
|
.map_err(|e| format!("Invalid scene-info-json: {}", e))?;
|
||||||
let skill_root = generate_scene_package(GenerateSceneRequest {
|
let skill_root = generate_scene_package(GenerateSceneRequest {
|
||||||
source_dir: args.source_dir,
|
source_dir: args.source_dir,
|
||||||
scene_id: args.scene_id,
|
scene_id: args.scene_id,
|
||||||
@@ -21,6 +25,7 @@ fn run() -> Result<(), String> {
|
|||||||
target_url: args.target_url,
|
target_url: args.target_url,
|
||||||
output_root: args.output_root,
|
output_root: args.output_root,
|
||||||
lessons_path: args.lessons_path,
|
lessons_path: args.lessons_path,
|
||||||
|
scene_info_json: scene_info,
|
||||||
})
|
})
|
||||||
.map_err(|err| err.to_string())?;
|
.map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
@@ -35,7 +40,8 @@ struct CliArgs {
|
|||||||
scene_kind: Option<SceneKind>,
|
scene_kind: Option<SceneKind>,
|
||||||
target_url: Option<String>,
|
target_url: Option<String>,
|
||||||
output_root: PathBuf,
|
output_root: PathBuf,
|
||||||
lessons_path: PathBuf,
|
lessons_path: Option<PathBuf>,
|
||||||
|
scene_info_json: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
||||||
@@ -46,6 +52,7 @@ fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
|||||||
let mut target_url = None;
|
let mut target_url = None;
|
||||||
let mut output_root = None;
|
let mut output_root = None;
|
||||||
let mut lessons_path = None;
|
let mut lessons_path = None;
|
||||||
|
let mut scene_info_json = None;
|
||||||
let mut pending_flag: Option<String> = None;
|
let mut pending_flag: Option<String> = None;
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
@@ -63,6 +70,7 @@ fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
|||||||
"--target-url" => target_url = Some(arg),
|
"--target-url" => target_url = Some(arg),
|
||||||
"--output-root" => output_root = Some(PathBuf::from(arg)),
|
"--output-root" => output_root = Some(PathBuf::from(arg)),
|
||||||
"--lessons" => lessons_path = Some(PathBuf::from(arg)),
|
"--lessons" => lessons_path = Some(PathBuf::from(arg)),
|
||||||
|
"--scene-info-json" => scene_info_json = Some(arg),
|
||||||
_ => return Err(format!("unsupported argument {flag}")),
|
_ => return Err(format!("unsupported argument {flag}")),
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -70,7 +78,7 @@ fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
|||||||
|
|
||||||
match arg.as_str() {
|
match arg.as_str() {
|
||||||
"--source-dir" | "--scene-id" | "--scene-name" | "--scene-kind" | "--target-url"
|
"--source-dir" | "--scene-id" | "--scene-name" | "--scene-kind" | "--target-url"
|
||||||
| "--output-root" | "--lessons" => {
|
| "--output-root" | "--lessons" | "--scene-info-json" => {
|
||||||
pending_flag = Some(arg);
|
pending_flag = Some(arg);
|
||||||
}
|
}
|
||||||
"--help" | "-h" => return Err(usage()),
|
"--help" | "-h" => return Err(usage()),
|
||||||
@@ -89,10 +97,11 @@ fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
|
|||||||
scene_kind,
|
scene_kind,
|
||||||
target_url,
|
target_url,
|
||||||
output_root: output_root.ok_or_else(usage)?,
|
output_root: output_root.ok_or_else(usage)?,
|
||||||
lessons_path: lessons_path.ok_or_else(usage)?,
|
lessons_path,
|
||||||
|
scene_info_json,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
fn usage() -> String {
|
||||||
"usage: sg_scene_generate --source-dir <scenario-dir> --scene-id <scene-id> --scene-name <display-name> [--scene-kind <report_collection|monitoring>] [--target-url <url>] --output-root <skill-staging-root> --lessons <lessons-toml>".to_string()
|
"usage: sg_scene_generate --source-dir <scenario-dir> --scene-id <scene-id> --scene-name <display-name> [--scene-kind <report_collection|monitoring>] [--target-url <url>] --output-root <skill-staging-root> [--lessons <lessons-toml>] [--scene-info-json '<json>']".to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -5,7 +6,53 @@ use std::path::{Path, PathBuf};
|
|||||||
use crate::generated_scene::analyzer::{
|
use crate::generated_scene::analyzer::{
|
||||||
analyze_scene_source_with_hint, AnalyzeSceneError, SceneKind, SceneSourceAnalysis,
|
analyze_scene_source_with_hint, AnalyzeSceneError, SceneKind, SceneSourceAnalysis,
|
||||||
};
|
};
|
||||||
use crate::generated_scene::lessons::load_generation_lessons;
|
use crate::generated_scene::lessons::{
|
||||||
|
load_generation_lessons, GenerationLessons, BUILTIN_REPORT_COLLECTION_LESSONS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct ApiEndpointJson {
|
||||||
|
pub name: String,
|
||||||
|
pub url: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub method: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct BusinessLogicJson {
|
||||||
|
#[serde(default)]
|
||||||
|
pub data_fetch: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub data_transform: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct SceneInfoJson {
|
||||||
|
#[serde(rename = "sceneId")]
|
||||||
|
pub scene_id: String,
|
||||||
|
#[serde(rename = "sceneName")]
|
||||||
|
pub scene_name: String,
|
||||||
|
#[serde(rename = "sceneKind", default)]
|
||||||
|
pub scene_kind: String,
|
||||||
|
#[serde(rename = "sourceSystem", default)]
|
||||||
|
pub source_system: Option<String>,
|
||||||
|
#[serde(rename = "expectedDomain", default)]
|
||||||
|
pub expected_domain: Option<String>,
|
||||||
|
#[serde(rename = "targetUrl", default)]
|
||||||
|
pub target_url: Option<String>,
|
||||||
|
#[serde(rename = "apiEndpoints", default)]
|
||||||
|
pub api_endpoints: Vec<ApiEndpointJson>,
|
||||||
|
#[serde(rename = "staticParams", default)]
|
||||||
|
pub static_params: HashMap<String, String>,
|
||||||
|
#[serde(rename = "columnDefs", default)]
|
||||||
|
pub column_defs: Vec<(String, String)>,
|
||||||
|
#[serde(rename = "entryMethod", default)]
|
||||||
|
pub entry_method: Option<String>,
|
||||||
|
#[serde(rename = "businessLogic", default)]
|
||||||
|
pub business_logic: Option<BusinessLogicJson>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct GenerateSceneRequest {
|
pub struct GenerateSceneRequest {
|
||||||
@@ -15,7 +62,8 @@ pub struct GenerateSceneRequest {
|
|||||||
pub scene_kind: Option<SceneKind>,
|
pub scene_kind: Option<SceneKind>,
|
||||||
pub target_url: Option<String>,
|
pub target_url: Option<String>,
|
||||||
pub output_root: PathBuf,
|
pub output_root: PathBuf,
|
||||||
pub lessons_path: PathBuf,
|
pub lessons_path: Option<PathBuf>,
|
||||||
|
pub scene_info_json: Option<SceneInfoJson>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -49,8 +97,16 @@ pub fn generate_scene_package(
|
|||||||
request: GenerateSceneRequest,
|
request: GenerateSceneRequest,
|
||||||
) -> Result<PathBuf, GenerateSceneError> {
|
) -> Result<PathBuf, GenerateSceneError> {
|
||||||
let analysis = analyze_scene_source_with_hint(&request.source_dir, request.scene_kind.clone())?;
|
let analysis = analyze_scene_source_with_hint(&request.source_dir, request.scene_kind.clone())?;
|
||||||
let lessons =
|
let (lessons, lessons_source): (GenerationLessons, String) = match &request.lessons_path {
|
||||||
load_generation_lessons(&request.lessons_path).map_err(GenerateSceneError::new)?;
|
Some(path) => (
|
||||||
|
load_generation_lessons(path).map_err(GenerateSceneError::new)?,
|
||||||
|
path.display().to_string(),
|
||||||
|
),
|
||||||
|
None => (
|
||||||
|
GenerationLessons::default_report_collection(),
|
||||||
|
BUILTIN_REPORT_COLLECTION_LESSONS.to_string(),
|
||||||
|
),
|
||||||
|
};
|
||||||
if !lessons.routing.require_exact_suffix
|
if !lessons.routing.require_exact_suffix
|
||||||
|| !lessons.bootstrap.require_expected_domain
|
|| !lessons.bootstrap.require_expected_domain
|
||||||
|| !lessons.bootstrap.require_target_url
|
|| !lessons.bootstrap.require_target_url
|
||||||
@@ -86,7 +142,7 @@ pub fn generate_scene_package(
|
|||||||
)?;
|
)?;
|
||||||
write_file(
|
write_file(
|
||||||
&scripts_dir.join(format!("{tool_name}.js")),
|
&scripts_dir.join(format!("{tool_name}.js")),
|
||||||
&browser_script(&request.scene_id, &analysis),
|
&browser_script(&request.scene_id, &analysis, request.scene_info_json.as_ref()),
|
||||||
)?;
|
)?;
|
||||||
write_file(
|
write_file(
|
||||||
&scripts_dir.join(format!("{tool_name}.test.js")),
|
&scripts_dir.join(format!("{tool_name}.test.js")),
|
||||||
@@ -97,7 +153,7 @@ pub fn generate_scene_package(
|
|||||||
&format!(
|
&format!(
|
||||||
"# Generation Lessons\n\nGenerated from `{}` with lessons `{}`.\n\nThis package is limited to report/collection browser_script scenes.\n",
|
"# Generation Lessons\n\nGenerated from `{}` with lessons `{}`.\n\nThis package is limited to report/collection browser_script scenes.\n",
|
||||||
request.source_dir.display(),
|
request.source_dir.display(),
|
||||||
request.lessons_path.display()
|
lessons_source
|
||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -204,13 +260,166 @@ fn default_org_dictionary() -> &'static str {
|
|||||||
"#
|
"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn browser_script(scene_id: &str, _analysis: &SceneSourceAnalysis) -> String {
|
fn browser_script_skeleton(scene_id: &str, _analysis: &SceneSourceAnalysis) -> String {
|
||||||
format!(
|
format!(
|
||||||
"function normalizePayload(payload) {{\n if (typeof payload === 'string') {{\n try {{ return JSON.parse(payload); }} catch (_) {{ return {{}}; }}\n }}\n return payload && typeof payload === 'object' ? payload : {{}};\n}}\n\nasync function buildBrowserEntrypointResult(args, deps = {{}}) {{\n const rows = typeof deps.collectRows === 'function'\n ? await deps.collectRows(args)\n : [{{\n org_label: args.org_label || '',\n org_code: args.org_code || '',\n period_mode: args.period_mode || '',\n period_value: args.period_value || '',\n value: ''\n }}];\n return {{\n type: 'report-artifact',\n report_name: '{}',\n status: rows.length > 0 ? 'ok' : 'empty',\n period: {{\n mode: args.period_mode,\n mode_code: args.period_mode_code,\n value: args.period_value,\n payload: normalizePayload(args.period_payload)\n }},\n org: {{ label: args.org_label, code: args.org_code }},\n column_defs: [\n ['org_label', '供电单位'],\n ['org_code', '供电单位编码'],\n ['period_mode', '统计周期类型'],\n ['period_value', '统计周期'],\n ['value', '采集值']\n ],\n columns: ['org_label', 'org_code', 'period_mode', 'period_value', 'value'],\n rows,\n counts: {{ detail_rows: rows.length }},\n partial_reasons: [],\n reasons: []\n }};\n}}\n\nif (typeof module !== 'undefined') {{\n module.exports = {{ buildBrowserEntrypointResult, normalizePayload }};\n}}\n\nif (typeof args !== 'undefined') {{\n return buildBrowserEntrypointResult(args);\n}}\n",
|
"function normalizePayload(payload) {{\n if (typeof payload === 'string') {{\n try {{ return JSON.parse(payload); }} catch (_) {{ return {{}}; }}\n }}\n return payload && typeof payload === 'object' ? payload : {{}};\n}}\n\nasync function buildBrowserEntrypointResult(args, deps = {{}}) {{\n const rows = typeof deps.collectRows === 'function'\n ? await deps.collectRows(args)\n : [{{\n org_label: args.org_label || '',\n org_code: args.org_code || '',\n period_mode: args.period_mode || '',\n period_value: args.period_value || '',\n value: ''\n }}];\n return {{\n type: 'report-artifact',\n report_name: '{}',\n status: rows.length > 0 ? 'ok' : 'empty',\n period: {{\n mode: args.period_mode,\n mode_code: args.period_mode_code,\n value: args.period_value,\n payload: normalizePayload(args.period_payload)\n }},\n org: {{ label: args.org_label, code: args.org_code }},\n column_defs: [\n ['org_label', '供电单位'],\n ['org_code', '供电单位编码'],\n ['period_mode', '统计周期类型'],\n ['period_value', '统计周期'],\n ['value', '采集值']\n ],\n columns: ['org_label', 'org_code', 'period_mode', 'period_value', 'value'],\n rows,\n counts: {{ detail_rows: rows.length }},\n partial_reasons: [],\n reasons: []\n }};\n}}\n\nif (typeof module !== 'undefined') {{\n module.exports = {{ buildBrowserEntrypointResult, normalizePayload }};\n}}\n\nif (typeof args !== 'undefined') {{\n return buildBrowserEntrypointResult(args);\n}}\n",
|
||||||
scene_id
|
scene_id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn browser_script(scene_id: &str, analysis: &SceneSourceAnalysis, scene_info: Option<&SceneInfoJson>) -> String {
|
||||||
|
match scene_info {
|
||||||
|
Some(info) if !info.api_endpoints.is_empty() || !info.column_defs.is_empty() => {
|
||||||
|
browser_script_with_business_logic(scene_id, analysis, info)
|
||||||
|
}
|
||||||
|
_ => browser_script_skeleton(scene_id, analysis),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn browser_script_with_business_logic(scene_id: &str, _analysis: &SceneSourceAnalysis, scene_info: &SceneInfoJson) -> String {
|
||||||
|
let api_endpoints_json = serde_json::to_string_pretty(&scene_info.api_endpoints).unwrap_or_else(|_| "[]".to_string());
|
||||||
|
let static_params_json = serde_json::to_string_pretty(&scene_info.static_params).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
let column_defs_json = serde_json::to_string_pretty(&scene_info.column_defs).unwrap_or_else(|_| "[]".to_string());
|
||||||
|
|
||||||
|
let column_names: Vec<&str> = scene_info.column_defs.iter().map(|(name, _)| name.as_str()).collect();
|
||||||
|
let columns_json = serde_json::to_string(&column_names).unwrap_or_else(|_| "[]".to_string());
|
||||||
|
|
||||||
|
format!(
|
||||||
|
r#"const API_ENDPOINTS = {api_endpoints_json};
|
||||||
|
|
||||||
|
const STATIC_PARAMS = {static_params_json};
|
||||||
|
|
||||||
|
const COLUMN_DEFS = {column_defs_json};
|
||||||
|
|
||||||
|
function normalizePayload(payload) {{
|
||||||
|
if (typeof payload === 'string') {{
|
||||||
|
try {{ return JSON.parse(payload); }} catch (_) {{ return {{}}; }}
|
||||||
|
}}
|
||||||
|
return payload && typeof payload === 'object' ? payload : {{}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
function validateArgs(args) {{
|
||||||
|
const errors = [];
|
||||||
|
if (!args.org_code) errors.push('Missing org_code');
|
||||||
|
if (!args.period_value) errors.push('Missing period_value');
|
||||||
|
return {{ valid: errors.length === 0, errors }};
|
||||||
|
}}
|
||||||
|
|
||||||
|
function buildRequest(args, endpoint) {{
|
||||||
|
const url = new URL(endpoint.url, window.location.origin);
|
||||||
|
const params = {{ ...STATIC_PARAMS, ...args }};
|
||||||
|
for (const [key, value] of Object.entries(params)) {{
|
||||||
|
if (value !== undefined && value !== null) {{
|
||||||
|
url.searchParams.set(key, String(value));
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return {{
|
||||||
|
url: url.toString(),
|
||||||
|
method: endpoint.method || 'GET',
|
||||||
|
headers: {{ 'Content-Type': 'application/json' }}
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
function normalizeRows(rawData) {{
|
||||||
|
if (!Array.isArray(rawData)) return [];
|
||||||
|
return rawData.map((row, index) => {{
|
||||||
|
const result = {{ _index: index }};
|
||||||
|
for (const [key, label] of COLUMN_DEFS) {{
|
||||||
|
result[key] = row[key] ?? '';
|
||||||
|
}}
|
||||||
|
return result;
|
||||||
|
}});
|
||||||
|
}}
|
||||||
|
|
||||||
|
function buildArtifact(args, rows) {{
|
||||||
|
return {{
|
||||||
|
type: 'report-artifact',
|
||||||
|
report_name: '{scene_id}',
|
||||||
|
status: rows.length > 0 ? 'ok' : 'empty',
|
||||||
|
period: {{
|
||||||
|
mode: args.period_mode,
|
||||||
|
mode_code: args.period_mode_code,
|
||||||
|
value: args.period_value,
|
||||||
|
payload: normalizePayload(args.period_payload)
|
||||||
|
}},
|
||||||
|
org: {{ label: args.org_label, code: args.org_code }},
|
||||||
|
column_defs: COLUMN_DEFS,
|
||||||
|
columns: {columns_json},
|
||||||
|
rows,
|
||||||
|
counts: {{ detail_rows: rows.length }},
|
||||||
|
partial_reasons: [],
|
||||||
|
reasons: []
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
const defaultDeps = {{
|
||||||
|
validatePageContext: async () => true,
|
||||||
|
queryData: async (args) => {{
|
||||||
|
const endpoint = API_ENDPOINTS[0];
|
||||||
|
if (!endpoint) throw new Error('No API endpoint configured');
|
||||||
|
const request = buildRequest(args, endpoint);
|
||||||
|
const response = await fetch(request.url, {{
|
||||||
|
method: request.method,
|
||||||
|
headers: request.headers
|
||||||
|
}});
|
||||||
|
if (!response.ok) throw new Error(`HTTP ${{response.status}}: ${{response.statusText}}`);
|
||||||
|
return response.json();
|
||||||
|
}}
|
||||||
|
}};
|
||||||
|
|
||||||
|
async function buildBrowserEntrypointResult(args, deps = defaultDeps) {{
|
||||||
|
const validation = validateArgs(args);
|
||||||
|
if (!validation.valid) {{
|
||||||
|
return {{
|
||||||
|
type: 'report-artifact',
|
||||||
|
report_name: '{scene_id}',
|
||||||
|
status: 'error',
|
||||||
|
error: 'Validation failed: ' + validation.errors.join(', '),
|
||||||
|
column_defs: COLUMN_DEFS,
|
||||||
|
columns: {columns_json},
|
||||||
|
rows: [],
|
||||||
|
counts: {{ detail_rows: 0 }},
|
||||||
|
partial_reasons: [],
|
||||||
|
reasons: validation.errors
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
|
||||||
|
try {{
|
||||||
|
const rawData = await (deps.queryData ? deps.queryData(args) : Promise.resolve([]));
|
||||||
|
const rows = normalizeRows(rawData);
|
||||||
|
return buildArtifact(args, rows);
|
||||||
|
}} catch (error) {{
|
||||||
|
return {{
|
||||||
|
type: 'report-artifact',
|
||||||
|
report_name: '{scene_id}',
|
||||||
|
status: 'error',
|
||||||
|
error: error.message,
|
||||||
|
column_defs: COLUMN_DEFS,
|
||||||
|
columns: {columns_json},
|
||||||
|
rows: [],
|
||||||
|
counts: {{ detail_rows: 0 }},
|
||||||
|
partial_reasons: [],
|
||||||
|
reasons: [error.message]
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined') {{
|
||||||
|
module.exports = {{ buildBrowserEntrypointResult, normalizePayload, validateArgs, buildRequest, normalizeRows, buildArtifact, API_ENDPOINTS, STATIC_PARAMS, COLUMN_DEFS }};
|
||||||
|
}}
|
||||||
|
|
||||||
|
if (typeof args !== 'undefined') {{
|
||||||
|
return buildBrowserEntrypointResult(args);
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
scene_id = scene_id,
|
||||||
|
api_endpoints_json = api_endpoints_json,
|
||||||
|
static_params_json = static_params_json,
|
||||||
|
column_defs_json = column_defs_json,
|
||||||
|
columns_json = columns_json
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn browser_script_test(tool_name: &str, _analysis: &SceneSourceAnalysis) -> String {
|
fn browser_script_test(tool_name: &str, _analysis: &SceneSourceAnalysis) -> String {
|
||||||
format!(
|
format!(
|
||||||
"const assert = require('assert');\nconst {{ buildBrowserEntrypointResult }} = require('./{}.js');\n\n(async () => {{\n const artifact = await buildBrowserEntrypointResult({{\n org_label: '国网兰州供电公司',\n org_code: '62401',\n period_mode: 'month',\n period_mode_code: '1',\n period_value: '2026-03',\n period_payload: '{{\"fdate\":\"2026-03\"}}'\n }});\n assert.equal(artifact.type, 'report-artifact');\n assert.ok(Array.isArray(artifact.column_defs));\n assert.equal(artifact.rows.length, 1);\n}})().catch((err) => {{\n console.error(err);\n process.exit(1);\n}});\n",
|
"const assert = require('assert');\nconst {{ buildBrowserEntrypointResult }} = require('./{}.js');\n\n(async () => {{\n const artifact = await buildBrowserEntrypointResult({{\n org_label: '国网兰州供电公司',\n org_code: '62401',\n period_mode: 'month',\n period_mode_code: '1',\n period_value: '2026-03',\n period_payload: '{{\"fdate\":\"2026-03\"}}'\n }});\n assert.equal(artifact.type, 'report-artifact');\n assert.ok(Array.isArray(artifact.column_defs));\n assert.equal(artifact.rows.length, 1);\n}})().catch((err) => {{\n console.error(err);\n process.exit(1);\n}});\n",
|
||||||
|
|||||||
Reference in New Issue
Block a user