wyreframe 0.1.0
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 +123 -0
- package/dist/index.d.ts +267 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +195 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
- package/src/parser/Core/Bounds.mjs +61 -0
- package/src/parser/Core/Bounds.res +65 -0
- package/src/parser/Core/Grid.mjs +268 -0
- package/src/parser/Core/Grid.res +265 -0
- package/src/parser/Core/Position.mjs +83 -0
- package/src/parser/Core/Position.res +54 -0
- package/src/parser/Core/Types.mjs +435 -0
- package/src/parser/Core/Types.res +331 -0
- package/src/parser/Core/__tests__/Bounds_test.mjs +326 -0
- package/src/parser/Core/__tests__/Bounds_test.res +412 -0
- package/src/parser/Core/__tests__/Grid_test.mjs +322 -0
- package/src/parser/Core/__tests__/Grid_test.res +319 -0
- package/src/parser/Core/__tests__/Types_test.mjs +614 -0
- package/src/parser/Core/__tests__/Types_test.res +650 -0
- package/src/parser/Detector/BoxTracer.mjs +302 -0
- package/src/parser/Detector/BoxTracer.res +374 -0
- package/src/parser/Detector/HierarchyBuilder.mjs +158 -0
- package/src/parser/Detector/HierarchyBuilder.res +315 -0
- package/src/parser/Detector/ShapeDetector.mjs +134 -0
- package/src/parser/Detector/ShapeDetector.res +236 -0
- package/src/parser/Detector/__tests__/BoxTracer_test.mjs +70 -0
- package/src/parser/Detector/__tests__/BoxTracer_test.res +92 -0
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.mjs +489 -0
- package/src/parser/Detector/__tests__/HierarchyBuilder_test.res +849 -0
- package/src/parser/Detector/__tests__/ShapeDetector_test.mjs +377 -0
- package/src/parser/Detector/__tests__/ShapeDetector_test.res +563 -0
- package/src/parser/Errors/ErrorContext.mjs +106 -0
- package/src/parser/Errors/ErrorContext.res +191 -0
- package/src/parser/Errors/ErrorMessages.mjs +289 -0
- package/src/parser/Errors/ErrorMessages.res +303 -0
- package/src/parser/Errors/ErrorTypes.mjs +105 -0
- package/src/parser/Errors/ErrorTypes.res +169 -0
- package/src/parser/Interactions/InteractionMerger.mjs +266 -0
- package/src/parser/Interactions/InteractionMerger.res +450 -0
- package/src/parser/Interactions/InteractionParser.mjs +88 -0
- package/src/parser/Interactions/InteractionParser.res +127 -0
- package/src/parser/Interactions/SimpleInteractionParser.mjs +278 -0
- package/src/parser/Interactions/SimpleInteractionParser.res +262 -0
- package/src/parser/Interactions/__tests__/InteractionMerger_test.mjs +576 -0
- package/src/parser/Interactions/__tests__/InteractionMerger_test.res +646 -0
- package/src/parser/Parser.gen.tsx +96 -0
- package/src/parser/Parser.mjs +212 -0
- package/src/parser/Parser.res +481 -0
- package/src/parser/Scanner/__tests__/Grid_manual.mjs +214 -0
- package/src/parser/Scanner/__tests__/Grid_manual.res +141 -0
- package/src/parser/Semantic/ASTBuilder.mjs +197 -0
- package/src/parser/Semantic/ASTBuilder.res +288 -0
- package/src/parser/Semantic/AlignmentCalc.mjs +41 -0
- package/src/parser/Semantic/AlignmentCalc.res +104 -0
- package/src/parser/Semantic/Elements/ButtonParser.mjs +58 -0
- package/src/parser/Semantic/Elements/ButtonParser.res +131 -0
- package/src/parser/Semantic/Elements/CheckboxParser.mjs +58 -0
- package/src/parser/Semantic/Elements/CheckboxParser.res +79 -0
- package/src/parser/Semantic/Elements/CodeTextParser.mjs +50 -0
- package/src/parser/Semantic/Elements/CodeTextParser.res +111 -0
- package/src/parser/Semantic/Elements/ElementParser.mjs +15 -0
- package/src/parser/Semantic/Elements/ElementParser.res +83 -0
- package/src/parser/Semantic/Elements/EmphasisParser.mjs +46 -0
- package/src/parser/Semantic/Elements/EmphasisParser.res +67 -0
- package/src/parser/Semantic/Elements/InputParser.mjs +41 -0
- package/src/parser/Semantic/Elements/InputParser.res +97 -0
- package/src/parser/Semantic/Elements/LinkParser.mjs +60 -0
- package/src/parser/Semantic/Elements/LinkParser.res +156 -0
- package/src/parser/Semantic/Elements/TextParser.mjs +19 -0
- package/src/parser/Semantic/Elements/TextParser.res +42 -0
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.mjs +189 -0
- package/src/parser/Semantic/Elements/__tests__/ButtonParser_test.res +257 -0
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.mjs +202 -0
- package/src/parser/Semantic/Elements/__tests__/CheckboxParser_test.res +250 -0
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.mjs +293 -0
- package/src/parser/Semantic/Elements/__tests__/CodeTextParser_manual.res +134 -0
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.mjs +253 -0
- package/src/parser/Semantic/Elements/__tests__/InputParser_test.res +304 -0
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.mjs +289 -0
- package/src/parser/Semantic/Elements/__tests__/LinkParser_test.res +402 -0
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.mjs +149 -0
- package/src/parser/Semantic/Elements/__tests__/TextParser_test.res +167 -0
- package/src/parser/Semantic/ParserRegistry.mjs +82 -0
- package/src/parser/Semantic/ParserRegistry.res +145 -0
- package/src/parser/Semantic/SemanticParser.mjs +850 -0
- package/src/parser/Semantic/SemanticParser.res +1368 -0
- package/src/parser/Semantic/__tests__/ASTBuilder_test.mjs +187 -0
- package/src/parser/Semantic/__tests__/ASTBuilder_test.res +192 -0
- package/src/parser/Semantic/__tests__/ParserRegistry_test.mjs +154 -0
- package/src/parser/Semantic/__tests__/ParserRegistry_test.res +191 -0
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.mjs +768 -0
- package/src/parser/Semantic/__tests__/SemanticParser_integration_test.res +1069 -0
- package/src/parser/Semantic/__tests__/SemanticParser_manual.mjs +1329 -0
- package/src/parser/Semantic/__tests__/SemanticParser_manual.res +544 -0
- package/src/parser/TestMain.mjs +21 -0
- package/src/parser/TestMain.res +14 -0
- package/src/parser/TextExtractor.mjs +179 -0
- package/src/parser/TextExtractor.res +264 -0
- package/src/parser/__tests__/GridScanner_integration.test.mjs +632 -0
- package/src/parser/__tests__/GridScanner_integration.test.res +816 -0
- package/src/parser/__tests__/Performance.test.mjs +244 -0
- package/src/parser/__tests__/Performance.test.res +371 -0
- package/src/parser/__tests__/PerformanceFixtures.mjs +200 -0
- package/src/parser/__tests__/PerformanceFixtures.res +284 -0
- package/src/parser/__tests__/WyreframeParser_integration.test.mjs +770 -0
- package/src/parser/__tests__/WyreframeParser_integration.test.res +1008 -0
- package/src/parser/__tests__/fixtures/alignment-test.txt +9 -0
- package/src/parser/__tests__/fixtures/all-elements.txt +16 -0
- package/src/parser/__tests__/fixtures/login-scene.txt +17 -0
- package/src/parser/__tests__/fixtures/multi-scene.txt +25 -0
- package/src/parser/__tests__/fixtures/nested-boxes.txt +15 -0
- package/src/parser/__tests__/fixtures/simple-box.txt +5 -0
- package/src/parser/__tests__/fixtures/with-dividers.txt +14 -0
- package/src/renderer/Renderer.gen.tsx +32 -0
- package/src/renderer/Renderer.mjs +391 -0
- package/src/renderer/Renderer.res +558 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/* TypeScript file generated from Parser.res by genType. */
|
|
2
|
+
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
/* tslint:disable */
|
|
5
|
+
|
|
6
|
+
import * as ParserJS from './Parser.mjs';
|
|
7
|
+
|
|
8
|
+
import type {ast as Types_ast} from '../../src/parser/Core/Types.gen';
|
|
9
|
+
|
|
10
|
+
import type {sceneInteractions as Types_sceneInteractions} from '../../src/parser/Core/Types.gen';
|
|
11
|
+
|
|
12
|
+
import type {t as ErrorTypes_t} from '../../src/parser/Errors/ErrorTypes.gen';
|
|
13
|
+
|
|
14
|
+
/** * Parse result type - either a successful AST or an array of parse errors.
|
|
15
|
+
* This Result type is compatible with TypeScript through GenType. */
|
|
16
|
+
export type parseResult =
|
|
17
|
+
{ TAG: "Ok"; _0: Types_ast }
|
|
18
|
+
| { TAG: "Error"; _0: ErrorTypes_t[] };
|
|
19
|
+
|
|
20
|
+
/** * Interaction parse result type. */
|
|
21
|
+
export type interactionResult =
|
|
22
|
+
{ TAG: "Ok"; _0: Types_sceneInteractions[] }
|
|
23
|
+
| { TAG: "Error"; _0: ErrorTypes_t[] };
|
|
24
|
+
|
|
25
|
+
/** * Main parsing function - parses mixed text containing wireframe and interactions.
|
|
26
|
+
*
|
|
27
|
+
* This function accepts a single text input that can contain:
|
|
28
|
+
* - ASCII wireframe (boxes with +---+, | |, etc.)
|
|
29
|
+
* - Interaction DSL (#id:, [Button]:, "Link": with properties)
|
|
30
|
+
* - Markdown, comments, or other noise (automatically ignored)
|
|
31
|
+
*
|
|
32
|
+
* The parser intelligently extracts wireframe and interaction content,
|
|
33
|
+
* allowing you to write everything in one place.
|
|
34
|
+
*
|
|
35
|
+
* Example:
|
|
36
|
+
* ```
|
|
37
|
+
* @scene: login
|
|
38
|
+
*
|
|
39
|
+
* +---------------------------+
|
|
40
|
+
* | 'WYREFRAME' |
|
|
41
|
+
* | +---------------------+ |
|
|
42
|
+
* | | #email | |
|
|
43
|
+
* | +---------------------+ |
|
|
44
|
+
* | [ Login ] |
|
|
45
|
+
* +---------------------------+
|
|
46
|
+
*
|
|
47
|
+
* #email:
|
|
48
|
+
* placeholder: "Enter your email"
|
|
49
|
+
*
|
|
50
|
+
* [Login]:
|
|
51
|
+
* @click -> goto(dashboard)
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @param text Mixed text containing wireframe and/or interactions
|
|
55
|
+
* @returns Result containing AST or array of parse errors
|
|
56
|
+
*
|
|
57
|
+
* REQ-20: Backward Compatibility
|
|
58
|
+
* REQ-21: Public API Stability
|
|
59
|
+
* REQ-28: Error Recovery (collect all errors) */
|
|
60
|
+
export const parse: (text:string) => parseResult = ParserJS.parse as any;
|
|
61
|
+
|
|
62
|
+
/** * Parse only the wireframe structure (no interactions).
|
|
63
|
+
* Convenience function that calls parseInternal(wireframe, None).
|
|
64
|
+
*
|
|
65
|
+
* @param wireframe ASCII wireframe string
|
|
66
|
+
* @returns Result containing AST or array of parse errors
|
|
67
|
+
*
|
|
68
|
+
* REQ-21: Public API Stability */
|
|
69
|
+
export const parseWireframe: (wireframe:string) => parseResult = ParserJS.parseWireframe as any;
|
|
70
|
+
|
|
71
|
+
/** * Parse only the interaction DSL.
|
|
72
|
+
* Useful when interactions are defined separately from the wireframe structure.
|
|
73
|
+
*
|
|
74
|
+
* @param dsl Interaction DSL string
|
|
75
|
+
* @returns Result containing scene interactions or array of parse errors
|
|
76
|
+
*
|
|
77
|
+
* REQ-21: Public API Stability */
|
|
78
|
+
export const parseInteractions: (dsl:string) => interactionResult = ParserJS.parseInteractions as any;
|
|
79
|
+
|
|
80
|
+
/** * Merge interaction definitions into an existing AST.
|
|
81
|
+
* Attaches properties and actions to elements based on element IDs.
|
|
82
|
+
*
|
|
83
|
+
* @param ast Base AST from wireframe parsing
|
|
84
|
+
* @param sceneInteractions Array of scene interactions to merge
|
|
85
|
+
* @returns AST with interactions merged into elements
|
|
86
|
+
*
|
|
87
|
+
* Integration requirement */
|
|
88
|
+
export const mergeInteractions: (ast:Types_ast, _sceneInteractions:Types_sceneInteractions[]) => Types_ast = ParserJS.mergeInteractions as any;
|
|
89
|
+
|
|
90
|
+
/** * Parser version string.
|
|
91
|
+
* Exported to TypeScript for version checking and compatibility validation. */
|
|
92
|
+
export const version: string = ParserJS.version as any;
|
|
93
|
+
|
|
94
|
+
/** * Parser implementation identifier.
|
|
95
|
+
* Useful for distinguishing between legacy JavaScript and new ReScript parser. */
|
|
96
|
+
export const implementation: string = ParserJS.implementation as any;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Grid from "./Core/Grid.mjs";
|
|
4
|
+
import * as ErrorTypes from "./Errors/ErrorTypes.mjs";
|
|
5
|
+
import * as Core__Array from "@rescript/core/src/Core__Array.mjs";
|
|
6
|
+
import * as ShapeDetector from "./Detector/ShapeDetector.mjs";
|
|
7
|
+
import * as TextExtractor from "./TextExtractor.mjs";
|
|
8
|
+
import * as ParserRegistry from "./Semantic/ParserRegistry.mjs";
|
|
9
|
+
import * as SemanticParser from "./Semantic/SemanticParser.mjs";
|
|
10
|
+
import * as InteractionMerger from "./Interactions/InteractionMerger.mjs";
|
|
11
|
+
import * as InteractionParser from "./Interactions/InteractionParser.mjs";
|
|
12
|
+
|
|
13
|
+
function scanGrid(wireframe) {
|
|
14
|
+
let normalized = wireframe.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
15
|
+
let lines = normalized.split("\n");
|
|
16
|
+
let grid = Grid.fromLines(lines);
|
|
17
|
+
return {
|
|
18
|
+
TAG: "Ok",
|
|
19
|
+
_0: grid
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let detectShapes = ShapeDetector.detect;
|
|
24
|
+
|
|
25
|
+
function convertBox(tracerBox) {
|
|
26
|
+
return {
|
|
27
|
+
name: tracerBox.name,
|
|
28
|
+
bounds: tracerBox.bounds,
|
|
29
|
+
children: tracerBox.children.map(convertBox)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseSemantics(grid, shapes) {
|
|
34
|
+
let registry = ParserRegistry.makeDefault();
|
|
35
|
+
let semanticBoxes = shapes.map(convertBox);
|
|
36
|
+
return SemanticParser.parse({
|
|
37
|
+
gridCells: grid.cells,
|
|
38
|
+
shapes: semanticBoxes,
|
|
39
|
+
registry: registry
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function parseInteractionsDSL(dsl) {
|
|
44
|
+
let interactions = InteractionParser.parse(dsl);
|
|
45
|
+
if (interactions.TAG === "Ok") {
|
|
46
|
+
return {
|
|
47
|
+
TAG: "Ok",
|
|
48
|
+
_0: interactions._0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
let match = interactions._0;
|
|
52
|
+
let error = ErrorTypes.make({
|
|
53
|
+
TAG: "InvalidInteractionDSL",
|
|
54
|
+
message: match.message,
|
|
55
|
+
position: match.position
|
|
56
|
+
}, undefined);
|
|
57
|
+
return {
|
|
58
|
+
TAG: "Error",
|
|
59
|
+
_0: [error]
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function mergeInteractionsIntoAST(ast, sceneInteractions) {
|
|
64
|
+
let mergedAst = InteractionMerger.mergeInteractions(ast, sceneInteractions);
|
|
65
|
+
if (mergedAst.TAG === "Ok") {
|
|
66
|
+
return mergedAst._0;
|
|
67
|
+
} else {
|
|
68
|
+
return ast;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseSingleScene(sceneContent, sceneMetadata, errors) {
|
|
73
|
+
let gridResult = scanGrid(sceneContent);
|
|
74
|
+
if (gridResult.TAG === "Ok") {
|
|
75
|
+
let grid = gridResult._0;
|
|
76
|
+
let shapesResult = ShapeDetector.detect(grid);
|
|
77
|
+
let shapes;
|
|
78
|
+
if (shapesResult.TAG === "Ok") {
|
|
79
|
+
shapes = shapesResult._0;
|
|
80
|
+
} else {
|
|
81
|
+
shapesResult._0.forEach(err => {
|
|
82
|
+
errors.push(err);
|
|
83
|
+
});
|
|
84
|
+
shapes = [];
|
|
85
|
+
}
|
|
86
|
+
let registry = ParserRegistry.makeDefault();
|
|
87
|
+
let semanticBoxes = shapes.map(convertBox);
|
|
88
|
+
let elements = semanticBoxes.flatMap(box => {
|
|
89
|
+
let boxElement = SemanticParser.parseBoxRecursive(box, grid.cells, registry);
|
|
90
|
+
if (boxElement.TAG === "Box") {
|
|
91
|
+
if (boxElement.name !== undefined) {
|
|
92
|
+
return [boxElement];
|
|
93
|
+
} else {
|
|
94
|
+
return boxElement.children;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
return [boxElement];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
id: sceneMetadata.id,
|
|
102
|
+
title: sceneMetadata.title,
|
|
103
|
+
transition: sceneMetadata.transition,
|
|
104
|
+
device: sceneMetadata.device,
|
|
105
|
+
elements: elements
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
gridResult._0.forEach(err => {
|
|
109
|
+
errors.push(err);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parseInternal(wireframe, interactions) {
|
|
114
|
+
let allErrors = [];
|
|
115
|
+
let sceneBlocks = SemanticParser.splitSceneBlocks(wireframe);
|
|
116
|
+
let trimmed = wireframe.trim();
|
|
117
|
+
if (sceneBlocks.length === 0 && trimmed === "") {
|
|
118
|
+
return {
|
|
119
|
+
TAG: "Ok",
|
|
120
|
+
_0: {
|
|
121
|
+
scenes: []
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let scenes = [];
|
|
126
|
+
sceneBlocks.forEach(block => {
|
|
127
|
+
let lines = block.split("\n");
|
|
128
|
+
let match = SemanticParser.parseSceneDirectives(lines);
|
|
129
|
+
let sceneContent = match[1].join("\n");
|
|
130
|
+
let scene = parseSingleScene(sceneContent, match[0], allErrors);
|
|
131
|
+
if (scene !== undefined) {
|
|
132
|
+
scenes.push(scene);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
let baseAst = {
|
|
137
|
+
scenes: scenes
|
|
138
|
+
};
|
|
139
|
+
let finalAst;
|
|
140
|
+
if (interactions !== undefined) {
|
|
141
|
+
let interactionsResult = parseInteractionsDSL(interactions);
|
|
142
|
+
if (interactionsResult.TAG === "Ok") {
|
|
143
|
+
finalAst = mergeInteractionsIntoAST(baseAst, interactionsResult._0);
|
|
144
|
+
} else {
|
|
145
|
+
interactionsResult._0.forEach(err => {
|
|
146
|
+
allErrors.push(err);
|
|
147
|
+
});
|
|
148
|
+
finalAst = baseAst;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
finalAst = baseAst;
|
|
152
|
+
}
|
|
153
|
+
let totalElements = Core__Array.reduce(finalAst.scenes, 0, (acc, scene) => acc + scene.elements.length | 0);
|
|
154
|
+
if (allErrors.length > 0 && totalElements === 0) {
|
|
155
|
+
return {
|
|
156
|
+
TAG: "Error",
|
|
157
|
+
_0: allErrors
|
|
158
|
+
};
|
|
159
|
+
} else {
|
|
160
|
+
return {
|
|
161
|
+
TAG: "Ok",
|
|
162
|
+
_0: finalAst
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function parse(text) {
|
|
168
|
+
let extracted = TextExtractor.extract(text);
|
|
169
|
+
let interactions = extracted.interactions.trim() === "" ? undefined : extracted.interactions;
|
|
170
|
+
return parseInternal(extracted.wireframe, interactions);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function parseWireframe(wireframe) {
|
|
174
|
+
return parseInternal(wireframe, undefined);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let parseInteractions = parseInteractionsDSL;
|
|
178
|
+
|
|
179
|
+
function mergeInteractions(ast, _sceneInteractions) {
|
|
180
|
+
return ast;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function collectErrors(gridErrors, shapeErrors, semanticErrors) {
|
|
184
|
+
return [
|
|
185
|
+
gridErrors,
|
|
186
|
+
shapeErrors,
|
|
187
|
+
semanticErrors
|
|
188
|
+
].flatMap(x => x);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let version = "0.1.0";
|
|
192
|
+
|
|
193
|
+
let implementation = "rescript";
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
scanGrid,
|
|
197
|
+
detectShapes,
|
|
198
|
+
convertBox,
|
|
199
|
+
parseSemantics,
|
|
200
|
+
parseInteractionsDSL,
|
|
201
|
+
mergeInteractionsIntoAST,
|
|
202
|
+
parseSingleScene,
|
|
203
|
+
parseInternal,
|
|
204
|
+
parse,
|
|
205
|
+
parseWireframe,
|
|
206
|
+
parseInteractions,
|
|
207
|
+
mergeInteractions,
|
|
208
|
+
collectErrors,
|
|
209
|
+
version,
|
|
210
|
+
implementation,
|
|
211
|
+
}
|
|
212
|
+
/* Grid Not a pure module */
|