@rex0220/formula-authoring-tools 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@ Projects/
30
30
  - `src/meta.ts` … tools の版、扱う計算式プラグイン(プラグイン ID `FORMULA_PLUGIN_ID`、封筒の `FORMULA_CONFIG_PLUGIN_ID`、版の下限 `MIN_PLUGIN_VERSION`)、API の版(`SUPPORTED_API_VERSIONS`)、API の契約(`REQUIRED_API`)
31
31
  - `src/commands/save.ts` … 保存の約束(formula MCP の `fml_save_settings` / `fml_update_fields` の本体。CLI は使わない)。新しい設定は同じ名前があれば保存しない、既存の設定は `fml_summary` の digest を照合して項目の行(`fieldcode`)を複数まとめて差し替える。normalize は Worker で行い、エラーがあれば確定しない。確定はロック付き(`commit-file.ts`)
32
32
  - `src/core.ts` … 共通の中核の入口(npm の `@rex0220/formula-authoring-tools/core`。formula MCP が使う。`CORE_API_VERSION` 2)。`scripts/build.mjs` が `dist/core.mjs` と `dist/types/` を作る。MCP が使う名前は `test/core-exports.test.mjs` で固定する
33
- - `scripts/vendor.mjs` … moment 2.24.0 を CDN から `vendor/` に取る(`vendor/moment.json` の SHA-256 と照合)。`scripts/build.mjs` … esbuild で `dist/cli.mjs` / `dist/eval-worker.mjs` / `dist/core.mjs`。`scripts/gen-docs.mjs` … `docs/`(設定ファイル仕様、関数一覧、functions.json、schema-manifest、既定のテストデータ)と `samples/users.json` を zip から機械生成
33
+ - `scripts/vendor.mjs` … moment 2.24.0 を CDN から `vendor/` に取る(`vendor/moment.json` の SHA-256 と照合)。`scripts/build.mjs` … esbuild で `dist/cli.mjs` / `dist/eval-worker.mjs` / `dist/core.mjs`。`scripts/gen-docs.mjs` … `docs/`(設定ファイル仕様、関数一覧、functions.json、schema-manifest、既定のテストデータ)と `samples/users.json` を zip から機械生成。`scripts/verify-patterns.mjs` + `scripts/pattern-cases.mjs` … 計算パターン集の例を同梱のサンプルアプリと架空の値で `try` に評価させ、関数一覧の使用例も評価して `docs/計算パターン_検証.md` を作る(`test/docs-sync.test.mjs` が最新と全部一致を確かめる = エンジンの版が変わったときの回帰検査)
34
34
  - `pending/` … print-craft から写してまだ計算式用にしていないもの(`diff.ts` / `normalize.ts` は計算式用の `src/commands/` が別にあるので使っていない)。npm には入らない
35
35
  - `test/` … `node --test`(src の .ts を直接読む。`test/helpers.mjs` が fixture の zip を読む。`test/fixtures/formula/` はテスト用アプリ 2305 の項目定義と設定)
36
36
 
@@ -60,7 +60,8 @@ npm pack --dry-run # 公開前に中身を確かめる(dist、vendor、LICENS
60
60
 
61
61
  ## 履歴
62
62
 
63
- - 0.3.0(2026-10): 式の試し計算 `try`(計画 25 章。formula MCP 0.2.0 の `fml_try`)。同梱のサンプルアプリ(`src/sample-app/`)に 1 行だけの設定を組んで normalize → calc。架空の項目と値(`src/commands/try-data.ts`: `--fields` で標本に項目を足す、`--data` で簡略形の値のレコード、`--app` で利用者のアプリの項目定義に架空の値)。`core` に `trySettings` / `SAMPLE_APP` / `describeSampleApp`、評価の仕事の kind `try`(`EvalJob` の `settingsText` / `settingsFile` / `fields` は try では省略できる)、`calcSettings` の `allowDefaultBaseUrl`。`CORE_API_VERSION` は 2 のまま(足しただけ)
63
+ - 0.3.1(2026-10): normalize がスペース項目(要素 ID のある SPACER)とヘッダーの行の計算式を `field.type` で誤って止めていたのを直した(設定画面は許す)。`try` でスペース項目を対象にできる(`--as sp1` / `SPACER`。標本に `sp1` を足した。レコードに値が無いので式の返り値をそのまま返す)
64
+ - 0.3.0(2026-10): 計算パターン集の例の検証(`docs/計算パターン_検証.md`。gen-docs)。式の試し計算 `try`(計画 25 章。formula MCP 0.2.0 の `fml_try`)。同梱のサンプルアプリ(`src/sample-app/`)に 1 行だけの設定を組んで normalize → calc。架空の項目と値(`src/commands/try-data.ts`: `--fields` で標本に項目を足す、`--data` で簡略形の値のレコード、`--app` で利用者のアプリの項目定義に架空の値)。`core` に `trySettings` / `SAMPLE_APP` / `describeSampleApp`、評価の仕事の kind `try`(`EvalJob` の `settingsText` / `settingsFile` / `fields` は try では省略できる)、`calcSettings` の `allowDefaultBaseUrl`。`CORE_API_VERSION` は 2 のまま(足しただけ)
64
65
  - 0.2.1(2026-10): formula MCP の Codex レビューへの対応。`updateFields` の `common` を共通の設定のキー(`COMMON_KEYS`)だけに。Worker の中の誤りの種類(`EvalError.kind`)と名前を中核が instanceof で決める(zip のコードの例外の name / constructor.name / 文を応答や標準エラーに出さない。`classifyEvalError` / `builtinErrorName`)。保存の結果の想定外の誤りも種類だけ(`zipCode`)。CLI の想定外の誤りは種類だけ(`FORMULA_DEBUG=1` で文とスタック)。接続の誤りの文の print-craft の名残を直した
65
66
  - 0.2.0(2026-10): formula MCP のための中核の入口(`CORE_API_VERSION` 2。CLI の動きは変えない)。`core` に workspace / connections / permission / commit-file / take / users の参照コード / JSON の誤りの文 / 行のキーを追加。`src/commands/save.ts`(`saveNewSettings` / `updateFields`)。`runEval` の `workerFile`(Worker の入口の絶対パス)と `captureOutput`(Worker の標準出力・標準エラーを親に流さず受け取る)、`loadEngine` の `vendorDir`(moment の置き場所)。評価の結果に `findings` と calc のレコードごとの行
66
67
  - 0.1.0(2026-10): 最初の公開。version / fields / record / records / pull / summary / diff / users / normalize / calc / take / edit / files。扱う計算式プラグイン Ver.101 以降、authoring API 1
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /*! @rex0220/formula-authoring-tools 0.3.0 (c) rex0220. MIT License. 計算式エンジンと計算式プラグインのコードは利用者の計算式プラグインプラグインの zip から読む(このファイルには含まれない)。commit cfbd850. */
2
+ /*! @rex0220/formula-authoring-tools 0.3.1 (c) rex0220. MIT License. 計算式エンジンと計算式プラグインのコードは利用者の計算式プラグインプラグインの zip から読む(このファイルには含まれない)。commit 3788114. */
3
3
 
4
4
  // src/cli.ts
5
5
  import { chmodSync, existsSync as existsSync9, mkdirSync as mkdirSync2, realpathSync as realpathSync5, writeFileSync as writeFileSync3 } from "node:fs";
@@ -355,7 +355,7 @@ function devMeta() {
355
355
  return { toolsVersion: pkg.version, pluginId: FORMULA_PLUGIN_ID, minPluginVersion: MIN_PLUGIN_VERSION, supportedApiVersions: [...SUPPORTED_API_VERSIONS], commit: gitCommit(AUTHORING_ROOT), builtAt: "", mode: "dev" };
356
356
  }
357
357
  function toolsMeta() {
358
- if (true) return JSON.parse('{"toolsVersion":"0.3.0","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"cfbd850","builtAt":"2026-10-18T05:24:49.527Z","mode":"build"}');
358
+ if (true) return JSON.parse('{"toolsVersion":"0.3.1","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"3788114","builtAt":"2026-10-18T08:08:27.541Z","mode":"build"}');
359
359
  return devMeta();
360
360
  }
361
361
 
@@ -3613,6 +3613,14 @@ var fields_default = {
3613
3613
  width: "250",
3614
3614
  innerHeight: "125"
3615
3615
  }
3616
+ },
3617
+ {
3618
+ type: "SPACER",
3619
+ elementId: "sp1",
3620
+ size: {
3621
+ width: "458",
3622
+ height: "163"
3623
+ }
3616
3624
  }
3617
3625
  ]
3618
3626
  },
@@ -3998,14 +4006,14 @@ var fields_default = {
3998
4006
  type: "RADIO_BUTTON",
3999
4007
  code: "T1_ラジオ",
4000
4008
  size: {
4001
- width: "150"
4009
+ width: "227"
4002
4010
  }
4003
4011
  },
4004
4012
  {
4005
4013
  type: "CHECK_BOX",
4006
4014
  code: "T1_チェック",
4007
4015
  size: {
4008
- width: "150"
4016
+ width: "227"
4009
4017
  }
4010
4018
  },
4011
4019
  {
@@ -4019,7 +4027,7 @@ var fields_default = {
4019
4027
  type: "DROP_DOWN",
4020
4028
  code: "T1_ドロップダウン",
4021
4029
  size: {
4022
- width: "150"
4030
+ width: "158"
4023
4031
  }
4024
4032
  },
4025
4033
  {
@@ -4125,14 +4133,14 @@ var fields_default = {
4125
4133
  type: "RADIO_BUTTON",
4126
4134
  code: "T2_ラジオ",
4127
4135
  size: {
4128
- width: "150"
4136
+ width: "227"
4129
4137
  }
4130
4138
  },
4131
4139
  {
4132
4140
  type: "CHECK_BOX",
4133
4141
  code: "T2_チェック",
4134
4142
  size: {
4135
- width: "150"
4143
+ width: "227"
4136
4144
  }
4137
4145
  },
4138
4146
  {
@@ -4146,7 +4154,7 @@ var fields_default = {
4146
4154
  type: "DROP_DOWN",
4147
4155
  code: "T2_ドロップダウン",
4148
4156
  size: {
4149
- width: "150"
4157
+ width: "158"
4150
4158
  }
4151
4159
  },
4152
4160
  {
@@ -5540,6 +5548,17 @@ var SAMPLE_APP = {
5540
5548
  function sampleApp() {
5541
5549
  return structuredClone(SAMPLE_APP);
5542
5550
  }
5551
+ function spacerIds(layout) {
5552
+ const out = [];
5553
+ for (const row of layout) {
5554
+ if (row.type === "GROUP" && Array.isArray(row.layout)) {
5555
+ out.push(...spacerIds(row.layout));
5556
+ continue;
5557
+ }
5558
+ for (const f of row.fields ?? []) if (f.type === "SPACER" && typeof f.elementId === "string" && f.elementId) out.push(f.elementId);
5559
+ }
5560
+ return out;
5561
+ }
5543
5562
  var tableRows = (record, code) => {
5544
5563
  const v = record[code]?.value;
5545
5564
  return Array.isArray(v) ? v.length : 0;
@@ -5554,6 +5573,7 @@ function describeSampleApp(targetTypes) {
5554
5573
  "項目(1 項目 1 行。○ = 計算式を設定できる型。テーブルの子は T1_ / T2_ の接頭辞):",
5555
5574
  listFields(fields, { targetTypes }),
5556
5575
  "",
5576
+ `スペース項目(要素 ID。as に要素 ID か SPACER。レコードに値は無く、式の返り値をそのまま返す): ${spacerIds(fields.layout).join(", ") || "無し"}`,
5557
5577
  "レコード(try の records で選ぶ。既定は 3 件とも):",
5558
5578
  ...records.map((r) => ` ${r.id}: ${r.label}。${tables.map((t) => `${t} ${tableRows(r.record, t)} 行`).join("、")}`),
5559
5579
  "ユーザー・組織・グループの値は既定のテストデータ(架空の 10 人。demo_user01 …)のコード"
@@ -5811,7 +5831,7 @@ async function normalizeSettings(input) {
5811
5831
  for (const r of rows) {
5812
5832
  const where = `${file} ${r.fieldcode}`;
5813
5833
  const t = typeOf(r);
5814
- if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
5834
+ if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t) && !isSpacerRow(r) && !isHeaderRow(r)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
5815
5835
  if (r.edit && (isHeaderRow(r) || isSpacerRow(r) || isGroupRow(r))) findings.error("field.flag", where, `${t} に「編集」は付けられない`);
5816
5836
  if (r.hide && (isHeaderRow(r) || isSpacerRow(r))) findings.error("field.flag", where, `${t} に「非表示」は付けられない`);
5817
5837
  if (r.state && r.formulaSet && isLookupRow(r)) findings.warning("field.lookup", where, "ルックアップ項目に計算式(ルックアップの値を上書きする)");
@@ -6494,12 +6514,33 @@ var TRY_MAX_FORMULA_CHARS = 4e3;
6494
6514
  var TRY_DEFAULT_AS = "TEXT";
6495
6515
  var TRY_OWN_RULES = /* @__PURE__ */ new Set(["misc.changed", "fieldno.screen", "size.bytes", "schema.derived"]);
6496
6516
  var isTable2 = (v) => Array.isArray(v) && v.every((r) => r && typeof r === "object" && "value" in r);
6517
+ function spacersOf(fields) {
6518
+ const out = [];
6519
+ const walk = (rows) => {
6520
+ for (const row of rows) {
6521
+ if (row.type === "GROUP" && Array.isArray(row.layout)) {
6522
+ walk(row.layout);
6523
+ continue;
6524
+ }
6525
+ for (const f of row.fields ?? []) if (f.type === "SPACER" && typeof f.elementId === "string" && f.elementId) out.push(f.elementId);
6526
+ }
6527
+ };
6528
+ walk(fields.layout);
6529
+ return out;
6530
+ }
6497
6531
  function resolveTryTarget(fields, targetTypes, as, table, referenced = /* @__PURE__ */ new Set()) {
6498
6532
  const props = fields.properties;
6499
6533
  const tables = Object.values(props).filter((p) => p.type === "SUBTABLE").map((p) => p.code).sort();
6500
6534
  const want = (as ?? TRY_DEFAULT_AS).trim();
6501
6535
  if (!want) throw new InputError("as が空(型 NUMBER / TEXT / DATE … か項目コード)");
6502
6536
  const upper = want.toUpperCase();
6537
+ const spacers = spacersOf(fields);
6538
+ const spacer = upper === "SPACER" || upper === "SPACE" ? spacers[0] : spacers.find((id) => id === want || `(${id})` === want);
6539
+ if (upper === "SPACER" || upper === "SPACE" || spacer !== void 0) {
6540
+ if (table !== void 0) throw new InputError("スペース項目はテーブルの中に置けない(table を外す)");
6541
+ if (spacer === void 0) throw new InputError("サンプルアプリに要素 ID のあるスペース項目が無い");
6542
+ return { code: `(${spacer})`, type: "SPACER", elementId: spacer };
6543
+ }
6503
6544
  const type = TYPE_ALIASES[upper] ?? (targetTypes.has(upper) ? upper : void 0);
6504
6545
  let scope = props;
6505
6546
  let tableCode;
@@ -6550,6 +6591,16 @@ function buildTryEnvelope(engine, fields, code, formula, lang) {
6550
6591
  pluginInfos: [{ fieldcode: code, state: true, formulaSet: formula, edit: false, hide: false, rank: "" }]
6551
6592
  };
6552
6593
  }
6594
+ function normalizedMarks(n, code) {
6595
+ const scan = n.scans.get(code);
6596
+ if (!scan) return [];
6597
+ const used = Object.keys(scan.functions);
6598
+ const marks = [];
6599
+ if (used.some((f) => /^(UINFO|OINFO|GINFO|OUSERS|GUSERS)$/.test(f))) marks.push("ユーザー情報は既定のテストデータ(架空)で計算(実機では変わる)");
6600
+ if (used.includes("EV_INFO")) marks.push("イベントに依る");
6601
+ if (used.some((f) => /^(RAND|RANDBETWEEN|NOW|TODAY|UUID)$/.test(f))) marks.push("再計算で変わる");
6602
+ return marks;
6603
+ }
6553
6604
  function plain(v) {
6554
6605
  try {
6555
6606
  const s = JSON.stringify(v);
@@ -6711,6 +6762,23 @@ async function trySettings(input) {
6711
6762
  }
6712
6763
  contextLine ||= c.contextLine;
6713
6764
  calcNotice ||= c.notice;
6765
+ if (target.type === "SPACER") {
6766
+ for (const r of c.records) {
6767
+ const src = picked.find((p) => p.id === r.id);
6768
+ engine.clearSinkCalls();
6769
+ const raw = src ? rawValueOf(engine, n.saved.pluginPP, structuredClone(src.record), stripped, target, input.evType, input.event) : null;
6770
+ const v = { record: r.id, value: raw };
6771
+ if (engine.sinkCalls().length) {
6772
+ v.failed = true;
6773
+ v.error = `実行時の sink が呼ばれた: ${engine.sinkCalls().map((s) => `${s.sink} ${s.detail}`.trim()).join(", ")}`;
6774
+ res.status = "failed";
6775
+ }
6776
+ engine.clearSinkCalls();
6777
+ res.values.push(v);
6778
+ }
6779
+ res.marks = [...normalizedMarks(n, target.code), "スペース項目(返り値をそのまま。表示は実機で)"];
6780
+ continue;
6781
+ }
6714
6782
  const lineCode = target.table ?? target.code;
6715
6783
  for (const r of c.records) {
6716
6784
  const line = r.lines.find((l) => l.fieldcode === lineCode);
@@ -6743,7 +6811,7 @@ async function trySettings(input) {
6743
6811
  if (extraFields.length) text2.push(`足した項目(架空): ${extraFields.join("、")}`);
6744
6812
  for (const r of picked) if (r.id.startsWith("d")) text2.push(`レコード ${r.id}: ${r.label}`);
6745
6813
  for (const r of results) {
6746
- const head = r.target ? `${r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
6814
+ const head = r.target ? `${r.target.type === "SPACER" ? `スペース項目 ${r.target.elementId}` : r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
6747
6815
  text2.push(`[${r.index}] ${head}${r.formula.replace(/\s*\n\s*/g, " ")}`);
6748
6816
  for (const v of r.values) text2.push(` レコード ${v.record}: ${short2(v.value)}${v.raw !== void 0 ? `(生の値 ${short2(v.raw)})` : ""}${v.error ? ` ! ${v.error}` : ""}${v.failed ? " ! 結果を採らない(実行時の sink)" : ""}`);
6749
6817
  if (r.marks.length) text2.push(` 印: ${r.marks.join("、")}`);
@@ -6945,7 +7013,7 @@ var USAGE = `使い方: npx @rex0220/formula-authoring-tools <command> [options]
6945
7013
  [--fields '<JSON>'] [--data '<JSON>'] [--base 3] [--app N]
6946
7014
  同梱のサンプルアプリ(全項目タイプ × 2、テーブル 2 つ、レコード 3 件 = 典型 / 端 / 空)に 1 行だけの設定を組んで
6947
7015
  検査と模擬の計算(関数の使い方や式の断片を確かめる。利用者のアプリは使わない)。--as は型(NUMBER / TEXT / DATE …。
6948
- 既定 TEXT = 文字列 1 行)か項目コード、テーブルの中で計算するなら --table テーブル1。
7016
+ 既定 TEXT = 文字列 1 行)か項目コード、テーブルの中で計算するなら --table テーブル1。スペース項目は --as sp1(返り値をそのまま)。
6949
7017
  --fields '[{"code":"単価","type":"NUMBER"},{"code":"分類","type":"DROP_DOWN","options":["明細","小計"]}]' で項目を足す、
6950
7018
  --data '[{"単価":100,"テーブル1":[{"T1_数値":1}]}]' で架空の値のレコード(土台は --base の標本。既定 3 = 空)、
6951
7019
  --app N で利用者のアプリの項目定義(fields/N.json かアプリのフォルダー)に --data の架空の値を当てる
package/dist/core.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! @rex0220/formula-authoring-tools/core 0.3.0 (c) rex0220. MIT License. 計算式エンジンと計算式プラグインのコードは利用者の計算式プラグインプラグインの zip から読む(このファイルには含まれない)。commit cfbd850. */
1
+ /*! @rex0220/formula-authoring-tools/core 0.3.1 (c) rex0220. MIT License. 計算式エンジンと計算式プラグインのコードは利用者の計算式プラグインプラグインの zip から読む(このファイルには含まれない)。commit 3788114. */
2
2
 
3
3
  // src/safe-path.ts
4
4
  import { lstatSync, realpathSync } from "node:fs";
@@ -190,7 +190,7 @@ function devMeta() {
190
190
  return { toolsVersion: pkg.version, pluginId: FORMULA_PLUGIN_ID, minPluginVersion: MIN_PLUGIN_VERSION, supportedApiVersions: [...SUPPORTED_API_VERSIONS], commit: gitCommit(AUTHORING_ROOT), builtAt: "", mode: "dev" };
191
191
  }
192
192
  function toolsMeta() {
193
- if (true) return JSON.parse('{"toolsVersion":"0.3.0","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"cfbd850","builtAt":"2026-10-18T05:24:49.527Z","mode":"build"}');
193
+ if (true) return JSON.parse('{"toolsVersion":"0.3.1","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"3788114","builtAt":"2026-10-18T08:08:27.541Z","mode":"build"}');
194
194
  return devMeta();
195
195
  }
196
196
 
@@ -2078,7 +2078,7 @@ async function normalizeSettings(input) {
2078
2078
  for (const r of rows) {
2079
2079
  const where = `${file} ${r.fieldcode}`;
2080
2080
  const t = typeOf(r);
2081
- if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
2081
+ if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t) && !isSpacerRow(r) && !isHeaderRow(r)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
2082
2082
  if (r.edit && (isHeaderRow(r) || isSpacerRow(r) || isGroupRow(r))) findings.error("field.flag", where, `${t} に「編集」は付けられない`);
2083
2083
  if (r.hide && (isHeaderRow(r) || isSpacerRow(r))) findings.error("field.flag", where, `${t} に「非表示」は付けられない`);
2084
2084
  if (r.state && r.formulaSet && isLookupRow(r)) findings.warning("field.lookup", where, "ルックアップ項目に計算式(ルックアップの値を上書きする)");
@@ -4269,6 +4269,14 @@ var fields_default = {
4269
4269
  width: "250",
4270
4270
  innerHeight: "125"
4271
4271
  }
4272
+ },
4273
+ {
4274
+ type: "SPACER",
4275
+ elementId: "sp1",
4276
+ size: {
4277
+ width: "458",
4278
+ height: "163"
4279
+ }
4272
4280
  }
4273
4281
  ]
4274
4282
  },
@@ -4654,14 +4662,14 @@ var fields_default = {
4654
4662
  type: "RADIO_BUTTON",
4655
4663
  code: "T1_ラジオ",
4656
4664
  size: {
4657
- width: "150"
4665
+ width: "227"
4658
4666
  }
4659
4667
  },
4660
4668
  {
4661
4669
  type: "CHECK_BOX",
4662
4670
  code: "T1_チェック",
4663
4671
  size: {
4664
- width: "150"
4672
+ width: "227"
4665
4673
  }
4666
4674
  },
4667
4675
  {
@@ -4675,7 +4683,7 @@ var fields_default = {
4675
4683
  type: "DROP_DOWN",
4676
4684
  code: "T1_ドロップダウン",
4677
4685
  size: {
4678
- width: "150"
4686
+ width: "158"
4679
4687
  }
4680
4688
  },
4681
4689
  {
@@ -4781,14 +4789,14 @@ var fields_default = {
4781
4789
  type: "RADIO_BUTTON",
4782
4790
  code: "T2_ラジオ",
4783
4791
  size: {
4784
- width: "150"
4792
+ width: "227"
4785
4793
  }
4786
4794
  },
4787
4795
  {
4788
4796
  type: "CHECK_BOX",
4789
4797
  code: "T2_チェック",
4790
4798
  size: {
4791
- width: "150"
4799
+ width: "227"
4792
4800
  }
4793
4801
  },
4794
4802
  {
@@ -4802,7 +4810,7 @@ var fields_default = {
4802
4810
  type: "DROP_DOWN",
4803
4811
  code: "T2_ドロップダウン",
4804
4812
  size: {
4805
- width: "150"
4813
+ width: "158"
4806
4814
  }
4807
4815
  },
4808
4816
  {
@@ -6196,6 +6204,17 @@ var SAMPLE_APP = {
6196
6204
  function sampleApp() {
6197
6205
  return structuredClone(SAMPLE_APP);
6198
6206
  }
6207
+ function spacerIds(layout) {
6208
+ const out = [];
6209
+ for (const row of layout) {
6210
+ if (row.type === "GROUP" && Array.isArray(row.layout)) {
6211
+ out.push(...spacerIds(row.layout));
6212
+ continue;
6213
+ }
6214
+ for (const f of row.fields ?? []) if (f.type === "SPACER" && typeof f.elementId === "string" && f.elementId) out.push(f.elementId);
6215
+ }
6216
+ return out;
6217
+ }
6199
6218
  var tableRows = (record, code) => {
6200
6219
  const v = record[code]?.value;
6201
6220
  return Array.isArray(v) ? v.length : 0;
@@ -6210,6 +6229,7 @@ function describeSampleApp(targetTypes) {
6210
6229
  "項目(1 項目 1 行。○ = 計算式を設定できる型。テーブルの子は T1_ / T2_ の接頭辞):",
6211
6230
  listFields(fields, { targetTypes }),
6212
6231
  "",
6232
+ `スペース項目(要素 ID。as に要素 ID か SPACER。レコードに値は無く、式の返り値をそのまま返す): ${spacerIds(fields.layout).join(", ") || "無し"}`,
6213
6233
  "レコード(try の records で選ぶ。既定は 3 件とも):",
6214
6234
  ...records.map((r) => ` ${r.id}: ${r.label}。${tables.map((t) => `${t} ${tableRows(r.record, t)} 行`).join("、")}`),
6215
6235
  "ユーザー・組織・グループの値は既定のテストデータ(架空の 10 人。demo_user01 …)のコード"
@@ -6631,12 +6651,33 @@ var TRY_MAX_FORMULA_CHARS = 4e3;
6631
6651
  var TRY_DEFAULT_AS = "TEXT";
6632
6652
  var TRY_OWN_RULES = /* @__PURE__ */ new Set(["misc.changed", "fieldno.screen", "size.bytes", "schema.derived"]);
6633
6653
  var isTable2 = (v) => Array.isArray(v) && v.every((r) => r && typeof r === "object" && "value" in r);
6654
+ function spacersOf(fields) {
6655
+ const out = [];
6656
+ const walk = (rows) => {
6657
+ for (const row of rows) {
6658
+ if (row.type === "GROUP" && Array.isArray(row.layout)) {
6659
+ walk(row.layout);
6660
+ continue;
6661
+ }
6662
+ for (const f of row.fields ?? []) if (f.type === "SPACER" && typeof f.elementId === "string" && f.elementId) out.push(f.elementId);
6663
+ }
6664
+ };
6665
+ walk(fields.layout);
6666
+ return out;
6667
+ }
6634
6668
  function resolveTryTarget(fields, targetTypes, as, table, referenced = /* @__PURE__ */ new Set()) {
6635
6669
  const props = fields.properties;
6636
6670
  const tables = Object.values(props).filter((p) => p.type === "SUBTABLE").map((p) => p.code).sort();
6637
6671
  const want = (as ?? TRY_DEFAULT_AS).trim();
6638
6672
  if (!want) throw new InputError("as が空(型 NUMBER / TEXT / DATE … か項目コード)");
6639
6673
  const upper = want.toUpperCase();
6674
+ const spacers = spacersOf(fields);
6675
+ const spacer = upper === "SPACER" || upper === "SPACE" ? spacers[0] : spacers.find((id) => id === want || `(${id})` === want);
6676
+ if (upper === "SPACER" || upper === "SPACE" || spacer !== void 0) {
6677
+ if (table !== void 0) throw new InputError("スペース項目はテーブルの中に置けない(table を外す)");
6678
+ if (spacer === void 0) throw new InputError("サンプルアプリに要素 ID のあるスペース項目が無い");
6679
+ return { code: `(${spacer})`, type: "SPACER", elementId: spacer };
6680
+ }
6640
6681
  const type = TYPE_ALIASES[upper] ?? (targetTypes.has(upper) ? upper : void 0);
6641
6682
  let scope = props;
6642
6683
  let tableCode;
@@ -6687,6 +6728,16 @@ function buildTryEnvelope(engine, fields, code, formula, lang) {
6687
6728
  pluginInfos: [{ fieldcode: code, state: true, formulaSet: formula, edit: false, hide: false, rank: "" }]
6688
6729
  };
6689
6730
  }
6731
+ function normalizedMarks(n, code) {
6732
+ const scan = n.scans.get(code);
6733
+ if (!scan) return [];
6734
+ const used = Object.keys(scan.functions);
6735
+ const marks = [];
6736
+ if (used.some((f) => /^(UINFO|OINFO|GINFO|OUSERS|GUSERS)$/.test(f))) marks.push("ユーザー情報は既定のテストデータ(架空)で計算(実機では変わる)");
6737
+ if (used.includes("EV_INFO")) marks.push("イベントに依る");
6738
+ if (used.some((f) => /^(RAND|RANDBETWEEN|NOW|TODAY|UUID)$/.test(f))) marks.push("再計算で変わる");
6739
+ return marks;
6740
+ }
6690
6741
  function plain(v) {
6691
6742
  try {
6692
6743
  const s = JSON.stringify(v);
@@ -6848,6 +6899,23 @@ async function trySettings(input) {
6848
6899
  }
6849
6900
  contextLine ||= c.contextLine;
6850
6901
  calcNotice ||= c.notice;
6902
+ if (target.type === "SPACER") {
6903
+ for (const r of c.records) {
6904
+ const src = picked.find((p) => p.id === r.id);
6905
+ engine.clearSinkCalls();
6906
+ const raw = src ? rawValueOf(engine, n.saved.pluginPP, structuredClone(src.record), stripped, target, input.evType, input.event) : null;
6907
+ const v = { record: r.id, value: raw };
6908
+ if (engine.sinkCalls().length) {
6909
+ v.failed = true;
6910
+ v.error = `実行時の sink が呼ばれた: ${engine.sinkCalls().map((s) => `${s.sink} ${s.detail}`.trim()).join(", ")}`;
6911
+ res.status = "failed";
6912
+ }
6913
+ engine.clearSinkCalls();
6914
+ res.values.push(v);
6915
+ }
6916
+ res.marks = [...normalizedMarks(n, target.code), "スペース項目(返り値をそのまま。表示は実機で)"];
6917
+ continue;
6918
+ }
6851
6919
  const lineCode = target.table ?? target.code;
6852
6920
  for (const r of c.records) {
6853
6921
  const line = r.lines.find((l) => l.fieldcode === lineCode);
@@ -6880,7 +6948,7 @@ async function trySettings(input) {
6880
6948
  if (extraFields.length) text2.push(`足した項目(架空): ${extraFields.join("、")}`);
6881
6949
  for (const r of picked) if (r.id.startsWith("d")) text2.push(`レコード ${r.id}: ${r.label}`);
6882
6950
  for (const r of results) {
6883
- const head = r.target ? `${r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
6951
+ const head = r.target ? `${r.target.type === "SPACER" ? `スペース項目 ${r.target.elementId}` : r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
6884
6952
  text2.push(`[${r.index}] ${head}${r.formula.replace(/\s*\n\s*/g, " ")}`);
6885
6953
  for (const v of r.values) text2.push(` レコード ${v.record}: ${short2(v.value)}${v.raw !== void 0 ? `(生の値 ${short2(v.raw)})` : ""}${v.error ? ` ! ${v.error}` : ""}${v.failed ? " ! 結果を採らない(実行時の sink)" : ""}`);
6886
6954
  if (r.marks.length) text2.push(` 印: ${r.marks.join("、")}`);
@@ -7524,6 +7592,7 @@ export {
7524
7592
  shapeLines,
7525
7593
  snapshotNameOf,
7526
7594
  snapshotOf,
7595
+ spacersOf,
7527
7596
  stronglyConnected,
7528
7597
  summarizeFields,
7529
7598
  summarizeRecord,
@@ -93,7 +93,7 @@ function devMeta() {
93
93
  return { toolsVersion: pkg.version, pluginId: FORMULA_PLUGIN_ID, minPluginVersion: MIN_PLUGIN_VERSION, supportedApiVersions: [...SUPPORTED_API_VERSIONS], commit: gitCommit(AUTHORING_ROOT), builtAt: "", mode: "dev" };
94
94
  }
95
95
  function toolsMeta() {
96
- if (true) return JSON.parse('{"toolsVersion":"0.3.0","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"cfbd850","builtAt":"2026-10-18T05:24:49.527Z","mode":"build"}');
96
+ if (true) return JSON.parse('{"toolsVersion":"0.3.1","pluginId":"dhgihghfgfmibkdldkeibboabfnmdpke","minPluginVersion":101,"supportedApiVersions":[1],"commit":"3788114","builtAt":"2026-10-18T08:08:27.541Z","mode":"build"}');
97
97
  return devMeta();
98
98
  }
99
99
 
@@ -996,7 +996,7 @@ async function normalizeSettings(input) {
996
996
  for (const r of rows) {
997
997
  const where = `${file} ${r.fieldcode}`;
998
998
  const t = typeOf(r);
999
- if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
999
+ if (r.formulaSet && r.formulaSet.trim() && !targetTypes.has(t) && !isSpacerRow(r) && !isHeaderRow(r)) findings.error("field.type", where, `${t} の項目には計算式を設定できない`);
1000
1000
  if (r.edit && (isHeaderRow(r) || isSpacerRow(r) || isGroupRow(r))) findings.error("field.flag", where, `${t} に「編集」は付けられない`);
1001
1001
  if (r.hide && (isHeaderRow(r) || isSpacerRow(r))) findings.error("field.flag", where, `${t} に「非表示」は付けられない`);
1002
1002
  if (r.state && r.formulaSet && isLookupRow(r)) findings.warning("field.lookup", where, "ルックアップ項目に計算式(ルックアップの値を上書きする)");
@@ -2319,6 +2319,14 @@ var fields_default = {
2319
2319
  width: "250",
2320
2320
  innerHeight: "125"
2321
2321
  }
2322
+ },
2323
+ {
2324
+ type: "SPACER",
2325
+ elementId: "sp1",
2326
+ size: {
2327
+ width: "458",
2328
+ height: "163"
2329
+ }
2322
2330
  }
2323
2331
  ]
2324
2332
  },
@@ -2704,14 +2712,14 @@ var fields_default = {
2704
2712
  type: "RADIO_BUTTON",
2705
2713
  code: "T1_ラジオ",
2706
2714
  size: {
2707
- width: "150"
2715
+ width: "227"
2708
2716
  }
2709
2717
  },
2710
2718
  {
2711
2719
  type: "CHECK_BOX",
2712
2720
  code: "T1_チェック",
2713
2721
  size: {
2714
- width: "150"
2722
+ width: "227"
2715
2723
  }
2716
2724
  },
2717
2725
  {
@@ -2725,7 +2733,7 @@ var fields_default = {
2725
2733
  type: "DROP_DOWN",
2726
2734
  code: "T1_ドロップダウン",
2727
2735
  size: {
2728
- width: "150"
2736
+ width: "158"
2729
2737
  }
2730
2738
  },
2731
2739
  {
@@ -2831,14 +2839,14 @@ var fields_default = {
2831
2839
  type: "RADIO_BUTTON",
2832
2840
  code: "T2_ラジオ",
2833
2841
  size: {
2834
- width: "150"
2842
+ width: "227"
2835
2843
  }
2836
2844
  },
2837
2845
  {
2838
2846
  type: "CHECK_BOX",
2839
2847
  code: "T2_チェック",
2840
2848
  size: {
2841
- width: "150"
2849
+ width: "227"
2842
2850
  }
2843
2851
  },
2844
2852
  {
@@ -2852,7 +2860,7 @@ var fields_default = {
2852
2860
  type: "DROP_DOWN",
2853
2861
  code: "T2_ドロップダウン",
2854
2862
  size: {
2855
- width: "150"
2863
+ width: "158"
2856
2864
  }
2857
2865
  },
2858
2866
  {
@@ -4661,12 +4669,33 @@ var TRY_MAX_FORMULA_CHARS = 4e3;
4661
4669
  var TRY_DEFAULT_AS = "TEXT";
4662
4670
  var TRY_OWN_RULES = /* @__PURE__ */ new Set(["misc.changed", "fieldno.screen", "size.bytes", "schema.derived"]);
4663
4671
  var isTable2 = (v) => Array.isArray(v) && v.every((r) => r && typeof r === "object" && "value" in r);
4672
+ function spacersOf(fields) {
4673
+ const out = [];
4674
+ const walk = (rows) => {
4675
+ for (const row of rows) {
4676
+ if (row.type === "GROUP" && Array.isArray(row.layout)) {
4677
+ walk(row.layout);
4678
+ continue;
4679
+ }
4680
+ for (const f of row.fields ?? []) if (f.type === "SPACER" && typeof f.elementId === "string" && f.elementId) out.push(f.elementId);
4681
+ }
4682
+ };
4683
+ walk(fields.layout);
4684
+ return out;
4685
+ }
4664
4686
  function resolveTryTarget(fields, targetTypes, as, table, referenced = /* @__PURE__ */ new Set()) {
4665
4687
  const props = fields.properties;
4666
4688
  const tables = Object.values(props).filter((p) => p.type === "SUBTABLE").map((p) => p.code).sort();
4667
4689
  const want = (as ?? TRY_DEFAULT_AS).trim();
4668
4690
  if (!want) throw new InputError("as が空(型 NUMBER / TEXT / DATE … か項目コード)");
4669
4691
  const upper = want.toUpperCase();
4692
+ const spacers = spacersOf(fields);
4693
+ const spacer = upper === "SPACER" || upper === "SPACE" ? spacers[0] : spacers.find((id) => id === want || `(${id})` === want);
4694
+ if (upper === "SPACER" || upper === "SPACE" || spacer !== void 0) {
4695
+ if (table !== void 0) throw new InputError("スペース項目はテーブルの中に置けない(table を外す)");
4696
+ if (spacer === void 0) throw new InputError("サンプルアプリに要素 ID のあるスペース項目が無い");
4697
+ return { code: `(${spacer})`, type: "SPACER", elementId: spacer };
4698
+ }
4670
4699
  const type = TYPE_ALIASES[upper] ?? (targetTypes.has(upper) ? upper : void 0);
4671
4700
  let scope = props;
4672
4701
  let tableCode;
@@ -4717,6 +4746,16 @@ function buildTryEnvelope(engine, fields, code, formula, lang) {
4717
4746
  pluginInfos: [{ fieldcode: code, state: true, formulaSet: formula, edit: false, hide: false, rank: "" }]
4718
4747
  };
4719
4748
  }
4749
+ function normalizedMarks(n, code) {
4750
+ const scan = n.scans.get(code);
4751
+ if (!scan) return [];
4752
+ const used = Object.keys(scan.functions);
4753
+ const marks = [];
4754
+ if (used.some((f) => /^(UINFO|OINFO|GINFO|OUSERS|GUSERS)$/.test(f))) marks.push("ユーザー情報は既定のテストデータ(架空)で計算(実機では変わる)");
4755
+ if (used.includes("EV_INFO")) marks.push("イベントに依る");
4756
+ if (used.some((f) => /^(RAND|RANDBETWEEN|NOW|TODAY|UUID)$/.test(f))) marks.push("再計算で変わる");
4757
+ return marks;
4758
+ }
4720
4759
  function plain(v) {
4721
4760
  try {
4722
4761
  const s = JSON.stringify(v);
@@ -4878,6 +4917,23 @@ async function trySettings(input) {
4878
4917
  }
4879
4918
  contextLine ||= c.contextLine;
4880
4919
  calcNotice ||= c.notice;
4920
+ if (target.type === "SPACER") {
4921
+ for (const r of c.records) {
4922
+ const src = picked.find((p) => p.id === r.id);
4923
+ engine.clearSinkCalls();
4924
+ const raw = src ? rawValueOf(engine, n.saved.pluginPP, structuredClone(src.record), stripped, target, input.evType, input.event) : null;
4925
+ const v = { record: r.id, value: raw };
4926
+ if (engine.sinkCalls().length) {
4927
+ v.failed = true;
4928
+ v.error = `実行時の sink が呼ばれた: ${engine.sinkCalls().map((s) => `${s.sink} ${s.detail}`.trim()).join(", ")}`;
4929
+ res.status = "failed";
4930
+ }
4931
+ engine.clearSinkCalls();
4932
+ res.values.push(v);
4933
+ }
4934
+ res.marks = [...normalizedMarks(n, target.code), "スペース項目(返り値をそのまま。表示は実機で)"];
4935
+ continue;
4936
+ }
4881
4937
  const lineCode = target.table ?? target.code;
4882
4938
  for (const r of c.records) {
4883
4939
  const line = r.lines.find((l) => l.fieldcode === lineCode);
@@ -4910,7 +4966,7 @@ async function trySettings(input) {
4910
4966
  if (extraFields.length) text2.push(`足した項目(架空): ${extraFields.join("、")}`);
4911
4967
  for (const r of picked) if (r.id.startsWith("d")) text2.push(`レコード ${r.id}: ${r.label}`);
4912
4968
  for (const r of results) {
4913
- const head = r.target ? `${r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
4969
+ const head = r.target ? `${r.target.type === "SPACER" ? `スペース項目 ${r.target.elementId}` : r.target.code}(${r.target.type}${r.target.table ? `。${r.target.table} の中` : ""})← ` : "";
4914
4970
  text2.push(`[${r.index}] ${head}${r.formula.replace(/\s*\n\s*/g, " ")}`);
4915
4971
  for (const v of r.values) text2.push(` レコード ${v.record}: ${short2(v.value)}${v.raw !== void 0 ? `(生の値 ${short2(v.raw)})` : ""}${v.error ? ` ! ${v.error}` : ""}${v.failed ? " ! 結果を採らない(実行時の sink)" : ""}`);
4916
4972
  if (r.marks.length) text2.push(` 印: ${r.marks.join("、")}`);
@@ -7,6 +7,8 @@
7
7
  * - 対象は式が参照していない項目を選ぶ(数値1 を使う式なら 数値2)。自己参照になるときのために、1 行の設定は各種設定の circular_refer を ON にして組む(設定画面の検査だけの決まり)
8
8
  * - 文脈は calc と同じ(イベント、ログインユーザー、mobile、ユーザー情報のテストデータ、policy の allowFunctions)。APP_URL はサンプルアプリの接続先(既定の例の URL)で評価する
9
9
  * - 走査の上の制限(副作用のある関数は policy の承認、EV_SET は不可)も calc と同じ。結果を採らない sink も同じ
10
+ * - スペース項目(レイアウトの SPACER で要素 ID のあるもの。設定画面の行はフィールドコード "(要素ID)")も対象にできる(as: "SPACER" か要素 ID)。レコードに値が無いので calc は通らず、
11
+ * 実機のスペースの処理と同じく式を評価した返り値(ARRAY(ラベル, 書式, 値, 書式) や HTML)をそのまま返す。表示は実機で(計画 25.5。2026-10-18 Takashi)
10
12
  * - 架空の項目と値(try-data.ts。計画 25.3): fields で標本に項目を足す(案 2)、data で簡略形の値のレコードを作る(案 1。土台は標本の base = 3 の空のレコード)、
11
13
  * appFields で利用者のアプリの項目定義に架空の値(案 3。標本のレコードは使わない。data が要る)
12
14
  */
@@ -32,6 +34,8 @@ export interface TryTarget {
32
34
  code: string;
33
35
  type: string;
34
36
  table?: string;
37
+ /** スペース項目のとき(type "SPACER")の要素 ID。code は "(要素ID)" */
38
+ elementId?: string;
35
39
  }
36
40
  export interface TryValue {
37
41
  /** レコード(標本は "1"〜"3"、架空の値は "d1"〜) */
@@ -102,9 +106,11 @@ export interface TryResult {
102
106
  summary: string;
103
107
  text: string;
104
108
  }
109
+ /** レイアウトのスペース項目(要素 ID のあるもの。グループ枠の中も)。設定画面の行と同じ順 */
110
+ export declare function spacersOf(fields: FieldsFile): string[];
105
111
  /**
106
112
  * 対象の項目を決める(型か項目コード、テーブルの中かどうか)。型のときは、式が参照していない項目を優先し、短いコードの順で最初(文字列1、数値1 …。数値1 を使う式なら 数値2)。
107
- * referenced は式の識別子(scanFormula)
113
+ * referenced は式の識別子(scanFormula)。スペース項目は as: "SPACER"(最初の要素 ID)か要素 ID("sp1" / "(sp1)")
108
114
  */
109
115
  export declare function resolveTryTarget(fields: FieldsFile, targetTypes: ReadonlySet<string>, as: string | undefined, table: string | undefined, referenced?: ReadonlySet<string>): TryTarget;
110
116
  /**
@@ -29,7 +29,7 @@ export { normalizeSettings, findCycles, stronglyConnected, type ContextNeeds, ty
29
29
  export { DEFAULT_EVENT, EVENT_RE, RECORDS_MAX, calcSettings, validateEvent, type CalcInput, type CalcLine, type CalcRecordResult, type CalcResult } from "./commands/calc.ts";
30
30
  export { takeInbox, type TakeResult } from "./commands/take.ts";
31
31
  export { SAMPLE_APP, describeSampleApp, sampleApp, type SampleApp, type SampleRecord } from "./sample-app.ts";
32
- export { TRY_DEFAULT_AS, TRY_MAX_FORMULAS, TRY_MAX_FORMULA_CHARS, buildTryEnvelope, resolveTryTarget, trySettings, type TryFormula, type TryFormulaResult, type TryInput, type TryResult, type TryTarget, type TryValue } from "./commands/try.ts";
32
+ export { TRY_DEFAULT_AS, TRY_MAX_FORMULAS, TRY_MAX_FORMULA_CHARS, buildTryEnvelope, resolveTryTarget, spacersOf, trySettings, type TryFormula, type TryFormulaResult, type TryInput, type TryResult, type TryTarget, type TryValue } from "./commands/try.ts";
33
33
  export { EXTRA_TYPES, TRY_MAX_DATA, TRY_MAX_EXTRA_FIELDS, TRY_MAX_OPTIONS, TRY_MAX_TABLE_ROWS, TRY_MAX_VALUE_CHARS, TYPE_ALIASES, applyData, canonicalType, checkDataList, convertValue, emptyRecordOf, extendFields, normalizeDefaults, type TryData, type TryFieldDef } from "./commands/try-data.ts";
34
34
  export { COMMON_KEYS, MAX_SAVE_INPUT_BYTES, MAX_UPDATE_ROWS, connectionStatusOf, digestOf, saveNewSettings, updateFields, type EvalSource, type SaveContext, type SaveResult, type SaveStatus } from "./commands/save.ts";
35
35
  export { DEFAULT_POLICY, POLICY_FILE, PolicyError, loadPolicy, parsePolicy, type Policy } from "./normalize/policy.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rex0220/formula-authoring-tools",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "rex0220 計算式プラグイン(kintone)の設定を AI で作るための CLI。利用者のプラグインの zip から authoring API と計算式エンジンを読んで Node で動く",
5
5
  "license": "MIT",
6
6
  "type": "module",