@udt/parser-utils 0.1.0 → 0.2.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/CHANGELOG.md +8 -0
- package/README.md +18 -14
- package/coverage/clover.xml +56 -50
- package/coverage/coverage-final.json +3 -3
- package/coverage/extractProperties.ts.html +8 -8
- package/coverage/index.html +22 -22
- package/coverage/index.ts.html +17 -11
- package/coverage/isJsonObject.ts.html +1 -1
- package/coverage/parseData.ts.html +74 -47
- package/dist/extractProperties.d.ts +4 -4
- package/dist/extractProperties.js +3 -3
- package/dist/index.js +2 -0
- package/dist/parseData.d.ts +23 -23
- package/dist/parseData.js +19 -12
- package/package.json +1 -1
- package/src/extractProperties.test.ts +2 -2
- package/src/extractProperties.ts +7 -7
- package/src/index.ts +2 -0
- package/src/parseData.test.ts +33 -36
- package/src/parseData.ts +50 -41
package/src/parseData.test.ts
CHANGED
|
@@ -19,10 +19,6 @@ interface TestDesignToken {
|
|
|
19
19
|
|
|
20
20
|
interface TestParentContext {
|
|
21
21
|
dummyData?: number;
|
|
22
|
-
|
|
23
|
-
// Used to pass in a mock addChild() function for
|
|
24
|
-
// mockParseGroupData() to use for testing
|
|
25
|
-
addChild?: AddChildFn<TestGroup, TestDesignToken>;
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
interface ParseDataCall {
|
|
@@ -53,7 +49,7 @@ const mockIsDesignTokenData = vi.fn<IsDesignTokenDataFn>(
|
|
|
53
49
|
);
|
|
54
50
|
|
|
55
51
|
const mockParseGroupData = vi.fn<
|
|
56
|
-
ParseGroupDataFn<TestGroup,
|
|
52
|
+
ParseGroupDataFn<TestGroup, TestParentContext>
|
|
57
53
|
>((_data, path, contextFromParent) => {
|
|
58
54
|
parseDataCalls.push({
|
|
59
55
|
type: "group",
|
|
@@ -65,12 +61,18 @@ const mockParseGroupData = vi.fn<
|
|
|
65
61
|
},
|
|
66
62
|
// pass through contextFromParent
|
|
67
63
|
contextForChildren: contextFromParent,
|
|
68
|
-
|
|
69
|
-
// pass through addChild
|
|
70
|
-
addChild: contextFromParent?.addChild,
|
|
71
64
|
};
|
|
72
65
|
});
|
|
73
66
|
|
|
67
|
+
const mockAddChildToGroup = vi.fn<AddChildFn<TestGroup, TestDesignToken>>(
|
|
68
|
+
(_parent, name, _child) => {
|
|
69
|
+
parseDataCalls.push({
|
|
70
|
+
type: "addChild",
|
|
71
|
+
name,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
74
76
|
const mockParseDesignTokenData = vi.fn<
|
|
75
77
|
ParseDesignTokenDataFn<TestDesignToken, TestParentContext>
|
|
76
78
|
>((_data, path, _contextFromParent) => {
|
|
@@ -81,20 +83,23 @@ const mockParseDesignTokenData = vi.fn<
|
|
|
81
83
|
return result;
|
|
82
84
|
});
|
|
83
85
|
|
|
86
|
+
const defaultParserConfig: ParserConfig<
|
|
87
|
+
TestDesignToken,
|
|
88
|
+
TestGroup,
|
|
89
|
+
TestParentContext
|
|
90
|
+
> = {
|
|
91
|
+
isDesignTokenData: mockIsDesignTokenData,
|
|
92
|
+
groupPropsToExtract: [],
|
|
93
|
+
parseGroupData: mockParseGroupData,
|
|
94
|
+
parseDesignTokenData: mockParseDesignTokenData,
|
|
95
|
+
};
|
|
96
|
+
|
|
84
97
|
describe("parseData()", () => {
|
|
85
|
-
|
|
86
|
-
TestDesignToken,
|
|
87
|
-
TestGroup,
|
|
88
|
-
TestParentContext
|
|
89
|
-
> = {
|
|
90
|
-
isDesignTokenData: mockIsDesignTokenData,
|
|
91
|
-
groupPropsToExtract: [],
|
|
92
|
-
parseGroupData: mockParseGroupData,
|
|
93
|
-
parseDesignTokenData: mockParseDesignTokenData,
|
|
94
|
-
};
|
|
98
|
+
let parserConfig: ParserConfig<TestDesignToken, TestGroup, TestParentContext>;
|
|
95
99
|
|
|
96
100
|
beforeEach(() => {
|
|
97
101
|
// Reset stuff
|
|
102
|
+
parserConfig = defaultParserConfig;
|
|
98
103
|
parseDataCalls = [];
|
|
99
104
|
parserConfig.groupPropsToExtract = [];
|
|
100
105
|
mockIsDesignTokenData.mockClear();
|
|
@@ -103,14 +108,14 @@ describe("parseData()", () => {
|
|
|
103
108
|
});
|
|
104
109
|
|
|
105
110
|
describe("parsing an empty group object", () => {
|
|
106
|
-
let parsedGroupOrToken: TestGroup | TestDesignToken;
|
|
111
|
+
let parsedGroupOrToken: TestGroup | TestDesignToken | undefined;
|
|
107
112
|
|
|
108
113
|
beforeEach(() => {
|
|
109
114
|
parsedGroupOrToken = parseData({}, parserConfig);
|
|
110
115
|
});
|
|
111
116
|
|
|
112
117
|
it("returns a group", () => {
|
|
113
|
-
expect(parsedGroupOrToken
|
|
118
|
+
expect(parsedGroupOrToken?.type).toBe("group");
|
|
114
119
|
});
|
|
115
120
|
|
|
116
121
|
it("calls isDesignTokenData function once", () => {
|
|
@@ -141,14 +146,14 @@ describe("parseData()", () => {
|
|
|
141
146
|
stuff: 123,
|
|
142
147
|
notAGroup: {},
|
|
143
148
|
};
|
|
144
|
-
let parsedGroupOrToken: TestGroup | TestDesignToken;
|
|
149
|
+
let parsedGroupOrToken: TestGroup | TestDesignToken | undefined;
|
|
145
150
|
|
|
146
151
|
beforeEach(() => {
|
|
147
152
|
parsedGroupOrToken = parseData(testTokenData, parserConfig);
|
|
148
153
|
});
|
|
149
154
|
|
|
150
155
|
it("returns a design token", () => {
|
|
151
|
-
expect(parsedGroupOrToken
|
|
156
|
+
expect(parsedGroupOrToken?.type).toBe("token");
|
|
152
157
|
});
|
|
153
158
|
|
|
154
159
|
it("does not call parseGroupData function", () => {
|
|
@@ -320,32 +325,24 @@ describe("parseData()", () => {
|
|
|
320
325
|
});
|
|
321
326
|
});
|
|
322
327
|
|
|
323
|
-
describe("using
|
|
328
|
+
describe("using addChildToGroup function", () => {
|
|
324
329
|
const testData = {
|
|
325
330
|
tokenA: { value: 1 },
|
|
326
331
|
tokenB: { value: 2 },
|
|
327
332
|
groupC: { tokenX: { value: 99 }, tokenY: { value: 100 } },
|
|
328
333
|
};
|
|
329
|
-
const mockAddChild = vi.fn<AddChildFn<TestGroup, TestDesignToken>>(
|
|
330
|
-
(name, _child) => {
|
|
331
|
-
parseDataCalls.push({
|
|
332
|
-
type: "addChild",
|
|
333
|
-
name,
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
);
|
|
337
|
-
const testContext: TestParentContext = { addChild: mockAddChild };
|
|
338
334
|
|
|
339
335
|
beforeEach(() => {
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
mockAddChildToGroup.mockClear();
|
|
337
|
+
parserConfig.addChildToGroup = mockAddChildToGroup;
|
|
338
|
+
parseData(testData, parserConfig);
|
|
342
339
|
});
|
|
343
340
|
|
|
344
|
-
it("calls
|
|
341
|
+
it("calls addChildToGroup for every child of every group", () => {
|
|
345
342
|
// Root group contains 3 children: "tokenA", "tokenB" and "groupC"
|
|
346
343
|
// "groupC" contains 2 children: "tokenX" and "tokenY"
|
|
347
344
|
// 3 + 2 = 5
|
|
348
|
-
expect(
|
|
345
|
+
expect(mockAddChildToGroup).toHaveBeenCalledTimes(5);
|
|
349
346
|
});
|
|
350
347
|
|
|
351
348
|
it("adds a nested group to its parent before parsing its children", () => {
|
package/src/parseData.ts
CHANGED
|
@@ -39,12 +39,14 @@ export type ParseDesignTokenDataFn<ParsedDesignToken, T> = (
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* A function that adds a parsed group or design token
|
|
42
|
-
* as a child of
|
|
42
|
+
* as a child of the given parsed group.
|
|
43
43
|
*
|
|
44
|
+
* @param parent The parent group to add a child to
|
|
44
45
|
* @param name The name of the child group or design token
|
|
45
|
-
* @param child The group or
|
|
46
|
+
* @param child The group or design token to add
|
|
46
47
|
*/
|
|
47
48
|
export type AddChildFn<ParsedGroup, ParsedDesignToken> = (
|
|
49
|
+
parent: ParsedGroup,
|
|
48
50
|
name: string,
|
|
49
51
|
child: ParsedGroup | ParsedDesignToken
|
|
50
52
|
) => void;
|
|
@@ -52,25 +54,15 @@ export type AddChildFn<ParsedGroup, ParsedDesignToken> = (
|
|
|
52
54
|
/**
|
|
53
55
|
* The return value of a `ParseGroupDataFn`.
|
|
54
56
|
*/
|
|
55
|
-
export interface ParseGroupResult<ParsedGroup,
|
|
57
|
+
export interface ParseGroupResult<ParsedGroup, T> {
|
|
56
58
|
/**
|
|
57
59
|
* The parsed representation of the group.
|
|
58
60
|
*
|
|
59
|
-
* May be
|
|
60
|
-
*
|
|
61
|
-
*
|
|
61
|
+
* May be omitted if there is no useful result to
|
|
62
|
+
* return and we only need to pass along context
|
|
63
|
+
* data.
|
|
62
64
|
*/
|
|
63
|
-
group
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Optional function that will add other parsed groups
|
|
67
|
-
* or design tokens as children of this parsed group.
|
|
68
|
-
*
|
|
69
|
-
* Intended for cases where the parsed representation
|
|
70
|
-
* of a group needs to contain its children. If not
|
|
71
|
-
* needed, this property can be omitted.
|
|
72
|
-
*/
|
|
73
|
-
addChild?: AddChildFn<ParsedGroup, ParsedDesignToken>;
|
|
65
|
+
group?: ParsedGroup;
|
|
74
66
|
|
|
75
67
|
/**
|
|
76
68
|
* Optional context data to be passed into the
|
|
@@ -96,15 +88,14 @@ export interface ParseGroupResult<ParsedGroup, ParsedDesignToken, T> {
|
|
|
96
88
|
* parsed the group containing this group.
|
|
97
89
|
*
|
|
98
90
|
* @returns The parsed representation of the group and,
|
|
99
|
-
* optionally,
|
|
100
|
-
*
|
|
101
|
-
* pass down when child data is parsed.
|
|
91
|
+
* optionally, some context data to pass down
|
|
92
|
+
* when child data is parsed.
|
|
102
93
|
*/
|
|
103
|
-
export type ParseGroupDataFn<ParsedGroup,
|
|
94
|
+
export type ParseGroupDataFn<ParsedGroup, T> = (
|
|
104
95
|
data: PlainObject,
|
|
105
96
|
path: string[],
|
|
106
97
|
contextFromParent?: T
|
|
107
|
-
) => ParseGroupResult<ParsedGroup,
|
|
98
|
+
) => ParseGroupResult<ParsedGroup, T>;
|
|
108
99
|
|
|
109
100
|
export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
|
|
110
101
|
/**
|
|
@@ -132,7 +123,7 @@ export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
|
|
|
132
123
|
* path, and should parse that data into whatever structure
|
|
133
124
|
* is desired.
|
|
134
125
|
*/
|
|
135
|
-
parseGroupData
|
|
126
|
+
parseGroupData?: ParseGroupDataFn<ParsedGroup, T>;
|
|
136
127
|
|
|
137
128
|
/**
|
|
138
129
|
* Function which is called for each design token
|
|
@@ -143,6 +134,16 @@ export interface ParserConfig<ParsedDesignToken, ParsedGroup, T> {
|
|
|
143
134
|
* desired.
|
|
144
135
|
*/
|
|
145
136
|
parseDesignTokenData: ParseDesignTokenDataFn<ParsedDesignToken, T>;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Optional function that will add parsed groups
|
|
140
|
+
* or design tokens as children of another parsed group.
|
|
141
|
+
*
|
|
142
|
+
* Intended for cases where the parsed representation
|
|
143
|
+
* of a group needs to contain its children. If not
|
|
144
|
+
* needed, this property can be omitted.
|
|
145
|
+
*/
|
|
146
|
+
addChildToGroup?: AddChildFn<ParsedGroup, ParsedDesignToken>;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
/**
|
|
@@ -192,8 +193,8 @@ function parseDataImpl<ParsedDesignToken, ParsedGroup, T>(
|
|
|
192
193
|
config: ParserConfig<ParsedDesignToken, ParsedGroup, T>,
|
|
193
194
|
contextFromParent?: T,
|
|
194
195
|
path: string[] = [],
|
|
195
|
-
|
|
196
|
-
): ParsedDesignToken | ParsedGroup {
|
|
196
|
+
parentGroup?: ParsedGroup
|
|
197
|
+
): ParsedDesignToken | ParsedGroup | undefined {
|
|
197
198
|
if (!isPlainObject(data)) {
|
|
198
199
|
throw new InvalidDataError(path, data);
|
|
199
200
|
}
|
|
@@ -203,38 +204,46 @@ function parseDataImpl<ParsedDesignToken, ParsedGroup, T>(
|
|
|
203
204
|
groupPropsToExtract,
|
|
204
205
|
parseGroupData,
|
|
205
206
|
parseDesignTokenData,
|
|
207
|
+
addChildToGroup,
|
|
206
208
|
} = config;
|
|
207
209
|
|
|
208
|
-
let groupOrToken: ParsedGroup | ParsedDesignToken;
|
|
210
|
+
let groupOrToken: ParsedGroup | ParsedDesignToken | undefined = undefined;
|
|
209
211
|
if (isDesignTokenData(data)) {
|
|
210
212
|
// looks like a token
|
|
211
213
|
groupOrToken = parseDesignTokenData(data, path, contextFromParent);
|
|
212
|
-
if (
|
|
213
|
-
|
|
214
|
+
if (addChildToGroup && path.length > 0 && parentGroup !== undefined) {
|
|
215
|
+
addChildToGroup(parentGroup, path[path.length - 1], groupOrToken);
|
|
214
216
|
}
|
|
215
217
|
} else {
|
|
216
218
|
// must be a group
|
|
217
|
-
const { extracted: groupData,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
groupData,
|
|
221
|
-
path,
|
|
222
|
-
contextFromParent
|
|
219
|
+
const { extracted: groupData, rest: children } = extractProperties(
|
|
220
|
+
data,
|
|
221
|
+
groupPropsToExtract
|
|
223
222
|
);
|
|
224
223
|
|
|
225
|
-
|
|
224
|
+
let contextForChildren: T | undefined;
|
|
225
|
+
if (parseGroupData) {
|
|
226
|
+
const parseResult = parseGroupData(groupData, path, contextFromParent);
|
|
227
|
+
contextForChildren = parseResult.contextForChildren;
|
|
228
|
+
groupOrToken = parseResult.group;
|
|
229
|
+
}
|
|
226
230
|
|
|
227
|
-
if (
|
|
228
|
-
|
|
231
|
+
if (
|
|
232
|
+
addChildToGroup &&
|
|
233
|
+
path.length > 0 &&
|
|
234
|
+
parentGroup !== undefined &&
|
|
235
|
+
groupOrToken !== undefined
|
|
236
|
+
) {
|
|
237
|
+
addChildToGroup(parentGroup, path[path.length - 1], groupOrToken);
|
|
229
238
|
}
|
|
230
239
|
|
|
231
|
-
for (const childName
|
|
240
|
+
for (const childName in children) {
|
|
232
241
|
parseDataImpl(
|
|
233
|
-
|
|
242
|
+
children[childName],
|
|
234
243
|
config,
|
|
235
244
|
contextForChildren,
|
|
236
245
|
[...path, childName],
|
|
237
|
-
|
|
246
|
+
groupOrToken
|
|
238
247
|
);
|
|
239
248
|
}
|
|
240
249
|
}
|
|
@@ -266,6 +275,6 @@ export function parseData<ParsedDesignToken, ParsedGroup, T>(
|
|
|
266
275
|
data: unknown,
|
|
267
276
|
config: ParserConfig<ParsedDesignToken, ParsedGroup, T>,
|
|
268
277
|
contextFromParent?: T
|
|
269
|
-
): ParsedDesignToken | ParsedGroup {
|
|
278
|
+
): ParsedDesignToken | ParsedGroup | undefined {
|
|
270
279
|
return parseDataImpl(data, config, contextFromParent);
|
|
271
280
|
}
|