UNPKG

@lark-project/cli

Version:

飞书项目插件开发工具

85 lines (84 loc) 4.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.preflightLocalConfig = void 0; const fs_extra_1 = require("fs-extra"); const validate_point_schema_1 = require("./validate-point-schema"); const write_local_point_config_1 = require("./write-local-point-config"); const get_plugin_app_type_1 = require("./get-plugin-app-type"); const validate_point_type_allowed_1 = require("./validate-point-type-allowed"); /** * Pre-build / pre-start gate: validate `point.config.local.json` against * the plugin schema before any expensive work (webpack compile, dev server * bootstrap, remote upload) starts. * * Why here, given `local-config set` already validates: that gate only fires * when the config flows through the proper plan→set workflow. When AI (or a * developer) directly edits `point.config.local.json` and runs `lpm start`/ * `lpm build`/`lpm release`, the schema check is skipped — webpack happily * compiles, the dev page boots, and the broken schema only surfaces when * release pushes to backend (or worse, silently produces a broken plugin). * * Gated purely on file existence: if `point.config.local.json` is in the * project, treat it as authoritative for local-mode runs and validate it. * `source_type` lives in `plugin.config.json` and is not a reliable trigger — * the CLI flag isn't always passed, and the file's mere presence already * signals intent to use local config. * * Why we write directly to process.stderr instead of going through `logger`: * the project's log4js console appender caches `process.stdout.write` / * `process.stderr.write` references at first flush, so test harnesses that * temporarily replace those writes (jest `IOCapture`) can't reliably observe * logger output. Preflight diagnostics are agent-readable error lists, so * stderr-direct keeps them deterministically capturable in tests + still * lands them on the correct sink for humans/CI. * * Exits the process with code 1 on validation errors so build/start fail fast * with a clear AI/developer-facing error list. */ async function preflightLocalConfig() { const filePath = (0, write_local_point_config_1.getLocalConfigPath)(); if (!(0, fs_extra_1.existsSync)(filePath)) return; let config; try { config = JSON.parse((0, fs_extra_1.readFileSync)(filePath, 'utf8')); } catch (e) { process.stderr.write(`point.config.local.json is not valid JSON: ${e.message}\n`); process.exit(1); } let result; try { result = await (0, validate_point_schema_1.validatePointConfig)(config); } catch (e) { // Schema unreachable (no auth, no fallback yaml, etc.) — warn but don't // block. We don't want a flaky network to break local builds. process.stderr.write(`Skip point.config.local.json schema check: ${e.message}\n`); return; } if (result.valid) { // schema 通过后再跑 app_type 硬卡。schema 只能保证形态,"AI 插件只能配专属点位" // 是 schema 之外的语义约束,必须在 preflight 也跑一次(防止用户绕过 local-config set // 直接写 point.config.local.json)。 const appType = (0, get_plugin_app_type_1.getPluginAppType)(); const allowed = (0, validate_point_type_allowed_1.validatePointTypeAllowed)(config, appType); if (!allowed.ok) { process.stderr.write('point.config.local.json violates plugin app_type constraints:\n'); for (const line of allowed.errors) { process.stderr.write(` ${line}\n`); } process.exit(1); } return; } process.stderr.write('point.config.local.json failed schema validation:\n'); const { lines } = (0, validate_point_schema_1.formatValidationErrors)(result, 'text'); for (const line of lines) { process.stderr.write(` ${line}\n`); } process.stderr.write('\nFix the errors above, or run "lpm ai validate --format json" for a structured listing.\n' + 'If you no longer need the local override, delete point.config.local.json.\n'); process.exit(1); } exports.preflightLocalConfig = preflightLocalConfig;