@podlite/schema 0.0.65 → 0.0.66

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.
@@ -1,2 +1,2 @@
1
- declare const _default: () => (tree: any) => any;
1
+ declare const _default: (opt?: {}) => (tree: any) => any;
2
2
  export default _default;
@@ -65,7 +65,7 @@ function applyRename(rows, rename, hasHeader) {
65
65
  }
66
66
  return [headerRow, ...rows.slice(1)];
67
67
  }
68
- function processDataTable(node, tree) {
68
+ function processDataTable(node, tree, report) {
69
69
  const attrs = (0, config_1.default)(node, {});
70
70
  const srcRaw = attrs.getFirstValue('src');
71
71
  const mimeAttr = attrs.getFirstValue('mime-type');
@@ -91,7 +91,7 @@ function processDataTable(node, tree) {
91
91
  if (scheme === 'data') {
92
92
  const dataBlock = (0, plugin_tables_1.findDataBlockByKey)(tree, target);
93
93
  if (!dataBlock) {
94
- console.warn(`[data-table] no =data block found for data:${target} rendered as empty`);
94
+ report('table-source-unreadable', `no =data block found for data:${target}, table rendered as empty`, node);
95
95
  return { ...node, name: 'table', content: [] };
96
96
  }
97
97
  if (mimeAttr) {
@@ -99,7 +99,7 @@ function processDataTable(node, tree) {
99
99
  }
100
100
  const dataMime = (0, config_1.default)(dataBlock, {}).getFirstValue('mime-type');
101
101
  if (!dataMime) {
102
- console.warn(`[data-table] =data block ${target} has no :mime-type rendered as empty`);
102
+ report('table-source-unreadable', `=data block ${target} has no :mime-type, table rendered as empty`, node);
103
103
  return { ...node, name: 'table', content: [] };
104
104
  }
105
105
  const parsed = (0, plugin_tables_1.parseMimeType)(dataMime);
@@ -123,12 +123,12 @@ function processDataTable(node, tree) {
123
123
  const isCsv = mimeType === 'text/csv';
124
124
  const isTsv = mimeType === 'text/tab-separated-values';
125
125
  if (!isCsv && !isTsv) {
126
- console.warn(`[data-table] unsupported mime-type ${mimeType} rendered as empty`);
126
+ report('table-source-unreadable', `unsupported mime-type ${mimeType}, table rendered as empty`, node);
127
127
  return { ...node, name: 'table', content: [] };
128
128
  }
129
129
  let rows = isCsv ? (0, plugin_tables_1.parseCsv)(csvText) : (0, plugin_tables_1.parseTsv)(csvText);
130
130
  if (rows.length === 0) {
131
- console.warn(`[data-table] ${isCsv ? 'CSV' : 'TSV'} parse produced no rows rendered as empty`);
131
+ report('table-source-unreadable', `${isCsv ? 'CSV' : 'TSV'} source has no rows, table rendered as empty`, node);
132
132
  return { ...node, name: 'table', content: [] };
133
133
  }
134
134
  if (columns) {
@@ -142,16 +142,17 @@ function processDataTable(node, tree) {
142
142
  name: 'table',
143
143
  content: (0, plugin_tables_1.csvToTableContent)(rows, hasHeader, attrs.getAllValues('allow')),
144
144
  };
145
- return (0, plugin_tables_1.normalizeCellCounts)(filledNode, 'data-table');
145
+ return (0, plugin_tables_1.normalizeCellCounts)(filledNode, 'data-table', report);
146
146
  }
147
- exports.default = () => tree => {
147
+ exports.default = (opt = {}) => tree => {
148
+ const report = (0, plugin_tables_1.makeTableReport)(opt);
148
149
  const transformer = (0, makeTransformer_1.default)({
149
150
  'data-table': node => {
150
151
  try {
151
- return processDataTable(node, tree);
152
+ return processDataTable(node, tree, report);
152
153
  }
153
154
  catch (err) {
154
- console.warn(`[data-table] ${err.message}`);
155
+ report('table-source-unreadable', err.message, node);
155
156
  return { ...node, name: 'table', content: [] };
156
157
  }
157
158
  },
@@ -41,49 +41,85 @@ const makeTransformer_1 = __importDefault(require("./helpers/makeTransformer"));
41
41
  const makeTransformer_2 = require("./helpers/makeTransformer");
42
42
  const config_1 = __importDefault(require("./helpers/config"));
43
43
  const parseAttributes_1 = require("./helpers/parseAttributes");
44
+ // `=config C<> :allow<I>` names a markup code, not a block: the trailing angles
45
+ // are the marker, and what it declares belongs to the code they name
46
+ const codeConfigOwner = (name) => typeof name === 'string' && /^[A-Z]<>$/.test(name) ? name[0] : null;
47
+ const collectAllowedIn = (content, inherited) => {
48
+ if (!Array.isArray(content))
49
+ return inherited;
50
+ let map = inherited;
51
+ for (const child of content) {
52
+ if (!child || typeof child !== 'object')
53
+ continue;
54
+ const node = child;
55
+ if (node.type !== 'config')
56
+ continue;
57
+ const owner = codeConfigOwner(node.name);
58
+ if (!owner)
59
+ continue;
60
+ if (map === inherited)
61
+ map = { ...inherited };
62
+ map[owner] = (0, config_1.default)(node, {}).getAllValues('allow');
63
+ }
64
+ return map;
65
+ };
44
66
  const middle = () => tree => {
45
67
  const transformerBlocks = (0, makeTransformer_1.default)({
46
68
  ':para': (n, ctx, visiter) => {
69
+ const allowedIn = ctx.allowedIn;
47
70
  return (0, makeTransformer_1.default)({
48
71
  ':text': (n, ctx) => {
49
- return fcparser.parse(n.value, { parseAttributes: parseAttributes_1.parseAttributes });
72
+ return fcparser.parse(n.value, { allowedIn, parseAttributes: parseAttributes_1.parseAttributes });
50
73
  },
51
74
  ':verbatim': (n, ctx) => {
52
- return fcparser.parse(n.value, { parseAttributes: parseAttributes_1.parseAttributes });
75
+ return fcparser.parse(n.value, { allowedIn, parseAttributes: parseAttributes_1.parseAttributes });
53
76
  },
54
77
  })(n, { ...ctx });
55
78
  return n;
56
79
  },
57
80
  ':block': (n, ctx, visiter) => {
81
+ // a block is a lexical scope: a code configured inside it stays inside
82
+ const allowedIn = collectAllowedIn('content' in n ? n.content : undefined, ctx.allowedIn || {});
58
83
  // only =pod may have childs blocks
59
84
  if ('name' in n && n.name === 'pod')
60
85
  return {
61
86
  ...n,
62
- content: visiter(n.content, ctx, visiter),
87
+ content: visiter(n.content, { ...ctx, allowedIn }, visiter),
63
88
  };
64
89
  const conf = (0, config_1.default)(n, ctx);
65
90
  const name = 'name' in n ? n.name : '';
66
91
  // Blocks whose content is verbatim by default — fcode parsing only
67
92
  // kicks in when :allow opts in (per spec, "Formatting within code blocks").
68
93
  const isVerbatimDefault = ['code', 'data', 'markdown', 'picture', 'formula'].includes(name);
69
- const allowValues = conf.getAllValues('allow');
70
94
  if ((0, makeTransformer_2.isNamedBlock)(name))
71
95
  return n;
96
+ // A table owns rows, and the text sits in the cells, so :allow written on
97
+ // the table reaches them. The nearest declaration wins: cell, row, table.
98
+ const inheritsAllow = name === 'row' || name === 'cell';
99
+ const declared = conf.exists('allow')
100
+ ? conf.getAllValues('allow')
101
+ : inheritsAllow
102
+ ? ctx.allowFromTable
103
+ : undefined;
104
+ const allowValues = declared || [];
105
+ const passesAllow = name === 'table' || name === 'row' ? declared : ctx.allowFromTable;
72
106
  if (isVerbatimDefault && allowValues.length === 0)
73
107
  return n;
74
- // a cell built from data carries its own set; declared empty means no code acts
75
- if (name === 'cell' && conf.exists('allow') && allowValues.length === 0)
76
- return n;
77
- const allowed = allowValues.sort();
108
+ // declared empty means no code acts on this text; nested blocks still get
109
+ // their turn, since a cell may declare a set of its own
110
+ const literal = inheritsAllow && declared !== undefined && declared.length === 0;
111
+ const allowed = [...allowValues].sort();
112
+ const inner = { ...ctx, allowedIn, allowFromTable: passesAllow };
78
113
  const transformer = (0, makeTransformer_1.default)({
79
- ':verbatim': (n, ctx) => fcparser.parse(n.value, { allowed, parseAttributes: parseAttributes_1.parseAttributes }),
80
- ':text': (n, ctx) => fcparser.parse(n.value, { allowed, parseAttributes: parseAttributes_1.parseAttributes }),
81
- ':block': (n, ctx) => transformerBlocks(n, { ...ctx }),
114
+ ':verbatim': (node, ctx) => literal ? node : fcparser.parse(node.value, { allowed, allowedIn, parseAttributes: parseAttributes_1.parseAttributes }),
115
+ ':text': (node, ctx) => literal ? node : fcparser.parse(node.value, { allowed, allowedIn, parseAttributes: parseAttributes_1.parseAttributes }),
116
+ ':block': (node, ctx) => transformerBlocks(node, { ...ctx, allowedIn, allowFromTable: passesAllow }),
82
117
  });
83
- return { ...n, content: transformer(n.content, { ...ctx }) };
118
+ return { ...n, content: transformer(n.content, inner) };
84
119
  },
85
120
  });
86
- return transformerBlocks(tree, {});
121
+ // a document needs no enclosing block, so the top level is a scope of its own
122
+ return transformerBlocks(tree, { allowedIn: collectAllowedIn(tree, {}) });
87
123
  };
88
124
  exports.default = middle;
89
125
  //# sourceMappingURL=plugin-formatting-codes.js.map
@@ -7,6 +7,8 @@ export declare function parseMimeType(raw: any): {
7
7
  export declare function findDataBlockByKey(tree: any, key: any): any;
8
8
  export declare function extractDataText(dataNode: any): any;
9
9
  export declare function csvToTableContent(csvRows: any, hasHeader?: boolean, allow?: string[]): any;
10
- export declare function normalizeCellCounts(tableNode: any, source?: string): any;
11
- declare const _default: () => (tree: any) => any;
10
+ export type TableReport = (code: string, message: string, node: any) => void;
11
+ export declare function makeTableReport(opt: any): TableReport;
12
+ export declare function normalizeCellCounts(tableNode: any, source?: string, report?: TableReport): any;
13
+ declare const _default: (opt?: {}) => (tree: any) => any;
12
14
  export default _default;
@@ -9,6 +9,7 @@ exports.parseMimeType = parseMimeType;
9
9
  exports.findDataBlockByKey = findDataBlockByKey;
10
10
  exports.extractDataText = extractDataText;
11
11
  exports.csvToTableContent = csvToTableContent;
12
+ exports.makeTableReport = makeTableReport;
12
13
  exports.normalizeCellCounts = normalizeCellCounts;
13
14
  /**
14
15
  * Plugin for fill term's for defn. From S26:
@@ -216,16 +217,27 @@ function csvToTableContent(csvRows, hasHeader = false, allow = []) {
216
217
  return buildRowBlock(cells, hasHeader && i === 0);
217
218
  });
218
219
  }
219
- // ─── Error recovery (design notes Rules 2-4) ───────────────────────────────
220
+ function makeTableReport(opt) {
221
+ const diagnostics = opt && Array.isArray(opt.diagnostics) ? opt.diagnostics : null;
222
+ return (code, message, node) => {
223
+ const location = node && node.location;
224
+ if (!diagnostics || !location)
225
+ return;
226
+ const seen = diagnostics.some(d => d.message === message && d.location.start.offset === location.start.offset);
227
+ if (!seen)
228
+ diagnostics.push({ severity: 'warning', code, message, location });
229
+ };
230
+ }
231
+ const noReport = () => { };
220
232
  // Rule 2 — table-level cell count validation. Pad short rows with empty
221
- // cells; truncate long rows. Emit a warning whenever a row is changed.
233
+ // cells; truncate long rows. Report whenever a row is changed.
222
234
  // Expected count is taken from the `:header` row if present, otherwise from
223
235
  // the row with the maximum cell count.
224
236
  //
225
237
  // Skipped when any cell uses `:colspan` or `:rowspan`: a spanning cell
226
238
  // occupies multiple columns, so naive cell counting would misreport row
227
239
  // width and drop legitimate spanned cells.
228
- function normalizeCellCounts(tableNode, source = 'table') {
240
+ function normalizeCellCounts(tableNode, source = 'table', report = noReport) {
229
241
  if (!tableNode || !Array.isArray(tableNode.content))
230
242
  return tableNode;
231
243
  const rows = tableNode.content.filter(c => c && c.type === 'block' && c.name === 'row');
@@ -252,13 +264,13 @@ function normalizeCellCounts(tableNode, source = 'table') {
252
264
  const padding = [];
253
265
  for (let i = cells.length; i < expected; i++)
254
266
  padding.push(buildCellBlock(''));
255
- console.warn(`[${source}] row has ${cells.length} cells, expected ${expected} padded with ${padding.length} empty`);
267
+ report('table-row-cells', `${source} row has ${cells.length} of ${expected} cells, padded with ${padding.length} empty. A row continued on the next line needs a blank line before the next row`, tableNode);
256
268
  mutated = true;
257
269
  return { ...child, content: [...child.content, ...padding] };
258
270
  }
259
271
  // cells.length > expected → truncate
260
272
  const dropped = cells.length - expected;
261
- console.warn(`[${source}] row has ${cells.length} cells, expected ${expected} truncated ${dropped}`);
273
+ report('table-row-cells', `${source} row has ${cells.length} of ${expected} cells, dropped ${dropped}`, tableNode);
262
274
  mutated = true;
263
275
  // Keep non-cell entries (e.g. blanklines) and the first `expected` cells
264
276
  let keepCells = expected;
@@ -282,7 +294,7 @@ function normalizeCellCounts(tableNode, source = 'table') {
282
294
  // for visible separators (`|` / `+`) surrounded by whitespace; lines without
283
295
  // any visible separator fall back to whitespace separation. Warns when more
284
296
  // than one separator type is observed within a single table.
285
- function detectMixedSeparators(lines) {
297
+ function detectMixedSeparators(lines, report = noReport, node = null) {
286
298
  const seen = new Set();
287
299
  for (const line of lines) {
288
300
  if (!line || typeof line !== 'string')
@@ -297,7 +309,7 @@ function detectMixedSeparators(lines) {
297
309
  break;
298
310
  }
299
311
  if (seen.size > 1) {
300
- console.warn(`[table] mixed separator types detected: ${Array.from(seen).join(', ')} recommend a single style`);
312
+ report('table-mixed-separators', `table mixes separator styles: ${Array.from(seen).join(', ')}. Keep one`, node);
301
313
  }
302
314
  }
303
315
  // Rule 4 — replace =table with =code block. Used when a referenced =data
@@ -448,9 +460,41 @@ const wrapImplicitCells = rowNode => {
448
460
  });
449
461
  return { ...rowNode, content: wrapped };
450
462
  };
463
+ // An abbreviated `=for row` owns its own paragraph, so cells written under it
464
+ // stay at table level and both the row and the cells lose their meaning. They
465
+ // are attached to the row above, and the author is told, per the same recovery
466
+ // contract that pads and truncates rows.
467
+ const attachOrphanCells = (tableNode, report = noReport) => {
468
+ const content = tableNode.content;
469
+ if (!Array.isArray(content))
470
+ return tableNode;
471
+ if (!content.some(c => c && c.type === 'block' && c.name === 'cell'))
472
+ return tableNode;
473
+ const out = [];
474
+ let openRow = null;
475
+ for (const child of content) {
476
+ if (child && child.type === 'block' && child.name === 'row') {
477
+ openRow = { ...child, content: Array.isArray(child.content) ? [...child.content] : [] };
478
+ out.push(openRow);
479
+ continue;
480
+ }
481
+ if (child && child.type === 'block' && child.name === 'cell') {
482
+ if (!openRow) {
483
+ openRow = { type: 'block', name: 'row', margin: child.margin || '', content: [] };
484
+ out.push(openRow);
485
+ }
486
+ openRow.content.push(child);
487
+ continue;
488
+ }
489
+ out.push(child);
490
+ }
491
+ report('table-cell-outside-row', 'a cell written outside a row was attached to the row above it; an abbreviated =for row holds only its own paragraph, so write =begin row and =end row around the cells', tableNode);
492
+ return { ...tableNode, content: out };
493
+ };
451
494
  const isStructured = tableNode => Array.isArray(tableNode.content) &&
452
495
  tableNode.content.some(c => c && c.type === 'block' && (c.name === 'row' || c.name === 'cell'));
453
- exports.default = () => tree => {
496
+ exports.default = (opt = {}) => tree => {
497
+ const report = makeTableReport(opt);
454
498
  const transformer = (0, makeTransformer_1.default)({
455
499
  table: (node, ctx, visiter) => {
456
500
  // CSV/data source reference (spec §1672):
@@ -461,7 +505,7 @@ exports.default = () => tree => {
461
505
  const dataBlock = findDataBlockByKey(tree, ref.target);
462
506
  if (!dataBlock) {
463
507
  // Rule 4: source not found → empty table (still a =table block)
464
- console.warn(`[table] no =data block found for data:${ref.target} rendered as empty`);
508
+ report('table-source-unreadable', `no =data block found for data:${ref.target}, table rendered as empty`, node);
465
509
  return { ...node, content: [] };
466
510
  }
467
511
  const rawMime = (0, config_1.default)(dataBlock, {}).getFirstValue('mime-type');
@@ -472,22 +516,23 @@ exports.default = () => tree => {
472
516
  const text = extractDataText(dataBlock);
473
517
  const rows = isCsv ? parseCsv(text) : parseTsv(text);
474
518
  if (rows.length === 0) {
475
- console.warn(`[table] ${isCsv ? 'CSV' : 'TSV'} parse produced no rows for data:${ref.target} rendered as empty`);
519
+ report('table-source-unreadable', `${isCsv ? 'CSV' : 'TSV'} source data:${ref.target} has no rows, table rendered as empty`, node);
476
520
  return { ...node, content: [] };
477
521
  }
478
522
  const hasHeader = mimeParams.header === 'present';
479
523
  const allow = (0, config_1.default)(node, {}).getAllValues('allow');
480
524
  const filledNode = { ...node, content: csvToTableContent(rows, hasHeader, allow) };
481
- return normalizeCellCounts(filledNode, `table data:${ref.target}`);
525
+ return normalizeCellCounts(filledNode, `table data:${ref.target}`, report);
482
526
  }
483
527
  // Rule 4: source not tabular → render as code block so content remains visible
484
- console.warn(`[table] =data :key<${ref.target}> has non-tabular mime-type ${rawMime || '(none)'} rendered as =code`);
528
+ report('table-source-unreadable', `=data :key<${ref.target}> has non-tabular mime-type ${rawMime || '(none)'}, rendered as =code`, node);
485
529
  return buildCodeFromDataBlock(node, dataBlock);
486
530
  }
487
531
  // structured mode: transform row children (wrap implicit cells), then
488
532
  // apply Rule 2 cell count normalization.
489
533
  if (isStructured(node)) {
490
- const transformedContent = (node.content || []).map(c => {
534
+ const attached = attachOrphanCells(node, report);
535
+ const transformedContent = (attached.content || []).map(c => {
491
536
  if (c && c.name === 'row')
492
537
  return wrapImplicitCells(c);
493
538
  return c;
@@ -495,7 +540,7 @@ exports.default = () => tree => {
495
540
  // a matched rule replaces the node without descending, so recurse
496
541
  // here or tables nested inside cells keep their raw text rows
497
542
  const recursed = visiter ? visiter(transformedContent, ctx) : transformedContent;
498
- return normalizeCellCounts({ ...node, content: recursed }, 'table');
543
+ return normalizeCellCounts({ ...attached, content: recursed }, 'table', report);
499
544
  }
500
545
  let rows = [];
501
546
  const collectValues = row => {
@@ -521,7 +566,7 @@ exports.default = () => tree => {
521
566
  const lines = flattenDeep(rows.map(splitToLines));
522
567
  const separators = flattenDeep(seps.map(splitToLines));
523
568
  // Rule 3: warn on mixed separator types within a single table
524
- detectMixedSeparators(lines);
569
+ detectMixedSeparators(lines, report, node);
525
570
  // collect text rows
526
571
  let textRows = [];
527
572
  (0, makeTransformer_1.default)({
@@ -560,7 +605,7 @@ exports.default = () => tree => {
560
605
  },
561
606
  'head:text': head => makeHeaderRow(splitToCells(head.value).map(makeCell)),
562
607
  })(node);
563
- return normalizeCellCounts(res, 'table');
608
+ return normalizeCellCounts(res, 'table', report);
564
609
  },
565
610
  });
566
611
  return transformer(tree, {});
package/lib/types.d.ts CHANGED
@@ -98,6 +98,7 @@ export interface Image {
98
98
  type: 'image';
99
99
  src: string;
100
100
  alt?: string;
101
+ link?: string;
101
102
  }
102
103
  export interface Toc {
103
104
  type: 'toc';
@@ -139,7 +140,7 @@ export interface RootBlock extends Omit<Block, 'location'> {
139
140
  }
140
141
  export interface ParseDiagnostic {
141
142
  severity: 'warning';
142
- code: 'value-unreadable' | 'directive-unreadable';
143
+ code: 'value-unreadable' | 'directive-unreadable' | 'table-row-cells' | 'table-cell-outside-row' | 'table-mixed-separators' | 'table-source-unreadable';
143
144
  message: string;
144
145
  location: Location;
145
146
  }
@@ -364,7 +365,7 @@ export interface BlockTable extends Omit<Block, 'content'> {
364
365
  export interface TableCell {
365
366
  name: 'cell';
366
367
  type: 'block';
367
- content: Array<string>;
368
+ content: Array<PodNode>;
368
369
  }
369
370
  export interface TableRow {
370
371
  name: 'row';
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.0.65";
1
+ export declare const version = "0.0.66";
package/lib/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // generated by scripts/inject-version.mjs — do not edit by hand
5
- exports.version = '0.0.65';
5
+ exports.version = '0.0.66';
6
6
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podlite/schema",
3
- "version": "0.0.65",
3
+ "version": "0.0.66",
4
4
  "description": "AST tools and schema for Podlite markup language — validate, traverse, and transform document trees",
5
5
  "main": "./lib/index.js",
6
6
  "sideEffects": false,
@@ -1348,6 +1348,10 @@
1348
1348
  "code": {
1349
1349
  "enum": [
1350
1350
  "directive-unreadable",
1351
+ "table-cell-outside-row",
1352
+ "table-mixed-separators",
1353
+ "table-row-cells",
1354
+ "table-source-unreadable",
1351
1355
  "value-unreadable"
1352
1356
  ],
1353
1357
  "type": "string"
@@ -1378,6 +1382,9 @@
1378
1382
  },
1379
1383
  "alt": {
1380
1384
  "type": "string"
1385
+ },
1386
+ "link": {
1387
+ "type": "string"
1381
1388
  }
1382
1389
  },
1383
1390
  "required": [
@@ -1529,7 +1536,7 @@
1529
1536
  "content": {
1530
1537
  "type": "array",
1531
1538
  "items": {
1532
- "type": "string"
1539
+ "$ref": "#/definitions/PodNode"
1533
1540
  }
1534
1541
  }
1535
1542
  },
@@ -1348,6 +1348,10 @@
1348
1348
  "code": {
1349
1349
  "enum": [
1350
1350
  "directive-unreadable",
1351
+ "table-cell-outside-row",
1352
+ "table-mixed-separators",
1353
+ "table-row-cells",
1354
+ "table-source-unreadable",
1351
1355
  "value-unreadable"
1352
1356
  ],
1353
1357
  "type": "string"
@@ -1378,6 +1382,9 @@
1378
1382
  },
1379
1383
  "alt": {
1380
1384
  "type": "string"
1385
+ },
1386
+ "link": {
1387
+ "type": "string"
1381
1388
  }
1382
1389
  },
1383
1390
  "required": [
@@ -1529,7 +1536,7 @@
1529
1536
  "content": {
1530
1537
  "type": "array",
1531
1538
  "items": {
1532
- "type": "string"
1539
+ "$ref": "#/definitions/PodNode"
1533
1540
  }
1534
1541
  }
1535
1542
  },