@jay-framework/compiler-jay-html 0.16.5 → 0.17.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/dist/index.js +114 -19
- package/docs/contract-file-format.md +6 -5
- package/docs/jay-html-docs.md +1 -0
- package/package.json +10 -9
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JayImportedType, isObjectType as isObjectType$1, isImportedType, isRecursiveType, JayUnknown, RenderFragment, Imports, Import, WithValidations, isArrayType as isArrayType$1, isAtomicType, isPromiseType, isEnumType, hasRefs, GenerateTarget, JayTypeAlias, JayUnionType, mkRefsTree, JayComponentType, JayHTMLType, mkRef, equalJayTypes, getModeFileExtension, RuntimeMode, nestRefs, mergeRefsTrees, SourceFileFormat, JayEnumType, JayObjectType, JayArrayType, JayPromiseType, resolvePrimitiveType, JayRecursiveType, JAY_CONTRACT_EXTENSION as JAY_CONTRACT_EXTENSION$1, ImportsFor, JAY_FULLSTACK_COMPONENTS, JayErrorType, JayOptionalType, JayRecordType, isOptionalType, isRecordType, resolvePluginComponent, resolvePluginManifest } from "@jay-framework/compiler-shared";
|
|
1
|
+
import { JayImportedType, isObjectType as isObjectType$1, isImportedType, isRecursiveType, JayUnknown, RenderFragment, Imports, Import, WithValidations, isArrayType as isArrayType$1, isAtomicType, isPromiseType, isEnumType, hasRefs, GenerateTarget, JayTypeAlias, JayUnionType, mkRefsTree, JayComponentType, JayHTMLType, mkRef, equalJayTypes, getModeFileExtension, isHtmlStringType, RuntimeMode, nestRefs, mergeRefsTrees, SourceFileFormat, JayEnumType, JayObjectType, JayArrayType, JayPromiseType, resolvePrimitiveType, JayRecursiveType, JAY_CONTRACT_EXTENSION as JAY_CONTRACT_EXTENSION$1, ImportsFor, JAY_FULLSTACK_COMPONENTS, JayErrorType, JayOptionalType, JayRecordType, isOptionalType, isRecordType, resolvePluginComponent, resolvePluginManifest } from "@jay-framework/compiler-shared";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { getLogger } from "@jay-framework/logger";
|
|
4
4
|
import fs from "fs/promises";
|
|
@@ -5919,6 +5919,7 @@ function assignHeadlessInstance(element, contractName, ref, parentCoord, parentS
|
|
|
5919
5919
|
);
|
|
5920
5920
|
if (significantChildren.length > 1) {
|
|
5921
5921
|
const wrapper = parse_2("<div></div>").querySelector("div");
|
|
5922
|
+
wrapper.setAttribute("style", "display: contents");
|
|
5922
5923
|
const children = [...element.childNodes];
|
|
5923
5924
|
element.innerHTML = "";
|
|
5924
5925
|
children.forEach((child) => wrapper.appendChild(child));
|
|
@@ -14366,6 +14367,23 @@ function filterContentNodes(childNodes, onlyIfMultiple = false) {
|
|
|
14366
14367
|
function textEscape$1(s) {
|
|
14367
14368
|
return s.replace(/'/g, "\\'");
|
|
14368
14369
|
}
|
|
14370
|
+
function decodeHtmlEntities(s) {
|
|
14371
|
+
return heExports.decode(s);
|
|
14372
|
+
}
|
|
14373
|
+
function findHtmlStringBindings(childNodes, variables) {
|
|
14374
|
+
const found = [];
|
|
14375
|
+
for (const child of childNodes) {
|
|
14376
|
+
if (child.nodeType !== NodeType.TEXT_NODE)
|
|
14377
|
+
continue;
|
|
14378
|
+
const text2 = (child.innerText || "").trim();
|
|
14379
|
+
for (const m of text2.matchAll(/\{([^}]+)\}/g)) {
|
|
14380
|
+
const accessor = parseAccessor(m[1], variables);
|
|
14381
|
+
if (isHtmlStringType(accessor.resolvedType))
|
|
14382
|
+
found.push(m[1]);
|
|
14383
|
+
}
|
|
14384
|
+
}
|
|
14385
|
+
return found;
|
|
14386
|
+
}
|
|
14369
14387
|
function escapeForJsString(s) {
|
|
14370
14388
|
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
14371
14389
|
}
|
|
@@ -18307,6 +18325,7 @@ function injectHeadfullFSTemplatesRecursive(fsElements, body, sourceDir, importR
|
|
|
18307
18325
|
for (const jayTag of jayTags) {
|
|
18308
18326
|
if (!jayTag.innerHTML.trim()) {
|
|
18309
18327
|
jayTag.set_content(jayHtmlBody.innerHTML);
|
|
18328
|
+
jayTag.setAttribute("style", "display: contents");
|
|
18310
18329
|
}
|
|
18311
18330
|
}
|
|
18312
18331
|
}
|
|
@@ -19680,7 +19699,6 @@ ${context.indent.firstLine} ${createBody})`,
|
|
|
19680
19699
|
const forEachFragment = forEachAccessor.render().map((_) => `(${paramName}: ${paramType}) => ${_}`);
|
|
19681
19700
|
const preAdoptRefNameGenerator = context.refNameGenerator.clone();
|
|
19682
19701
|
const itemChildNodes = filterContentNodes(element.childNodes);
|
|
19683
|
-
`${forEachVariables.currentVar}.${trackBy}`;
|
|
19684
19702
|
const itemContext = {
|
|
19685
19703
|
...context,
|
|
19686
19704
|
variables: forEachVariables,
|
|
@@ -19855,7 +19873,6 @@ ${indent.firstLine})`,
|
|
|
19855
19873
|
dynamicRef: true,
|
|
19856
19874
|
insideSlowForEach: true
|
|
19857
19875
|
};
|
|
19858
|
-
buildRenderContext(itemContext);
|
|
19859
19876
|
const itemChildNodes = filterContentNodes(element.childNodes);
|
|
19860
19877
|
const childFragments = itemChildNodes.map((child) => renderHydrateNode(child, itemContext));
|
|
19861
19878
|
const nonEmptyChildren = childFragments.filter((f) => f.rendered.trim());
|
|
@@ -19964,7 +19981,7 @@ function renderHydrateHeadlessInstance(element, context, renderContext, contract
|
|
|
19964
19981
|
const coordResult = extractHeadlessCoordinate(element, contractName);
|
|
19965
19982
|
if (isValidationError(coordResult))
|
|
19966
19983
|
return coordResult;
|
|
19967
|
-
const { instanceCoord,
|
|
19984
|
+
const { instanceCoord, coordinateSuffix, childScopeId } = coordResult;
|
|
19968
19985
|
const isInsideForEach = context.insideFastForEach;
|
|
19969
19986
|
let coordinateKey2;
|
|
19970
19987
|
if (isInsideForEach) {
|
|
@@ -20216,6 +20233,21 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
|
|
|
20216
20233
|
textFragment = null;
|
|
20217
20234
|
}
|
|
20218
20235
|
}
|
|
20236
|
+
const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
|
|
20237
|
+
const isHtmlStringChild = htmlStringBindings.length > 0;
|
|
20238
|
+
if (isHtmlStringChild && (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE)) {
|
|
20239
|
+
return new RenderFragment("", Imports.none(), [
|
|
20240
|
+
`html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
|
|
20241
|
+
]);
|
|
20242
|
+
}
|
|
20243
|
+
if (isHtmlStringChild) {
|
|
20244
|
+
const text2 = (childNodes[0].innerText || "").trim();
|
|
20245
|
+
if (text2 !== `{${htmlStringBindings[0]}}`) {
|
|
20246
|
+
return new RenderFragment("", Imports.none(), [
|
|
20247
|
+
`html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
|
|
20248
|
+
]);
|
|
20249
|
+
}
|
|
20250
|
+
}
|
|
20219
20251
|
const hasInteractiveChildren = childNodes.some(
|
|
20220
20252
|
(child) => child.nodeType === NodeType.ELEMENT_NODE && (isConditional(child) && conditionIsInteractive(
|
|
20221
20253
|
child.getAttribute("if"),
|
|
@@ -20285,7 +20317,7 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
|
|
|
20285
20317
|
let childImports = Imports.none();
|
|
20286
20318
|
const childValidations = [];
|
|
20287
20319
|
const childRefs = [];
|
|
20288
|
-
childNodes.forEach((child
|
|
20320
|
+
childNodes.forEach((child) => {
|
|
20289
20321
|
if (child.nodeType === NodeType.ELEMENT_NODE) {
|
|
20290
20322
|
const frag = renderHydrateNode(child, context);
|
|
20291
20323
|
if (frag.rendered.trim()) {
|
|
@@ -20322,6 +20354,16 @@ function renderHydrateElementContent(element, context, renderContext, coordinate
|
|
|
20322
20354
|
mergeRefsTrees(...childRefs, renderedRef.refs)
|
|
20323
20355
|
);
|
|
20324
20356
|
}
|
|
20357
|
+
if (isHtmlStringChild && textFragment && !hasDynamicAttrs) {
|
|
20358
|
+
const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
|
|
20359
|
+
const refSuffix2 = renderedRef.rendered ? `, ${renderedRef.rendered}` : "";
|
|
20360
|
+
return new RenderFragment(
|
|
20361
|
+
`${indent.firstLine}adoptElement("${coordinate}", ${attributes2.rendered}, [dh(${accessor})]${refSuffix2})`,
|
|
20362
|
+
Imports.for(Import.adoptElement).plus(Import.dynamicHtml).plus(textFragment.imports.minus(Import.dynamicText)).plus(renderedRef.imports).plus(attributes2.imports),
|
|
20363
|
+
[...textFragment.validations, ...renderedRef.validations, ...attributes2.validations],
|
|
20364
|
+
renderedRef.refs
|
|
20365
|
+
);
|
|
20366
|
+
}
|
|
20325
20367
|
if (textFragment && !hasDynamicAttrs) {
|
|
20326
20368
|
const accessor = textFragment.rendered.replace(/^dt\(/, "").replace(/\)$/, "");
|
|
20327
20369
|
if (refName) {
|
|
@@ -20455,7 +20497,32 @@ function renderFunctionDeclaration(preRenderType) {
|
|
|
20455
20497
|
return `export declare function render(options?: RenderElementOptions): ${preRenderType}`;
|
|
20456
20498
|
}
|
|
20457
20499
|
function renderTextNode(variables, text2, indent) {
|
|
20458
|
-
return parseTextExpression(textEscape$1(text2), variables).map(
|
|
20500
|
+
return parseTextExpression(textEscape$1(decodeHtmlEntities(text2)), variables).map(
|
|
20501
|
+
(_) => indent.firstLine + _
|
|
20502
|
+
);
|
|
20503
|
+
}
|
|
20504
|
+
function tryRenderHtmlStringChild(childNodes, variables, indent) {
|
|
20505
|
+
const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
|
|
20506
|
+
if (htmlStringBindings.length === 0)
|
|
20507
|
+
return null;
|
|
20508
|
+
if (childNodes.length !== 1 || childNodes[0].nodeType !== NodeType.TEXT_NODE) {
|
|
20509
|
+
return new RenderFragment("", Imports.none(), [
|
|
20510
|
+
`html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
|
|
20511
|
+
]);
|
|
20512
|
+
}
|
|
20513
|
+
const text2 = (childNodes[0].innerText || "").trim();
|
|
20514
|
+
if (text2 !== `{${htmlStringBindings[0]}}`) {
|
|
20515
|
+
return new RenderFragment("", Imports.none(), [
|
|
20516
|
+
`html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with other content`
|
|
20517
|
+
]);
|
|
20518
|
+
}
|
|
20519
|
+
const accessor = parseAccessor(htmlStringBindings[0], variables);
|
|
20520
|
+
const accessorCode = accessor.render();
|
|
20521
|
+
return new RenderFragment(
|
|
20522
|
+
`${indent.firstLine}dh(${variables.currentVar} => ${accessorCode.rendered})`,
|
|
20523
|
+
Imports.for(Import.dynamicHtml).plus(accessorCode.imports),
|
|
20524
|
+
[...accessor.validations, ...accessorCode.validations]
|
|
20525
|
+
);
|
|
20459
20526
|
}
|
|
20460
20527
|
function renderStyleAttribute(styleString, variables) {
|
|
20461
20528
|
const { declarations, hasDynamic } = parseStyleDeclarations(styleString, variables);
|
|
@@ -20695,7 +20762,7 @@ function renderChildCompRef$1(element, { dynamicRef, variables, refNameGenerator
|
|
|
20695
20762
|
return new RenderFragment(`${constName}()`, Imports.for(), [], refs);
|
|
20696
20763
|
}
|
|
20697
20764
|
function renderNode(node2, context) {
|
|
20698
|
-
let { variables,
|
|
20765
|
+
let { variables, importedSandboxedSymbols, indent, importerMode } = context;
|
|
20699
20766
|
function de2(tagName, attributes2, children, ref, currIndent = indent) {
|
|
20700
20767
|
const refWithPrefixComma = ref.rendered.length ? `, ${ref.rendered}` : "";
|
|
20701
20768
|
const tagFunc = tagToNamespace(tagName, true, context.namespaces);
|
|
@@ -20753,6 +20820,22 @@ function renderNode(node2, context) {
|
|
|
20753
20820
|
};
|
|
20754
20821
|
}
|
|
20755
20822
|
let childNodes = filterContentNodes(node2.childNodes, true);
|
|
20823
|
+
const htmlStringChild = tryRenderHtmlStringChild(
|
|
20824
|
+
childNodes,
|
|
20825
|
+
contextForChildren.variables,
|
|
20826
|
+
contextForChildren.indent.child().noFirstLineBreak()
|
|
20827
|
+
);
|
|
20828
|
+
if (htmlStringChild) {
|
|
20829
|
+
let attributes22 = renderAttributes$1(htmlElement, contextForChildren);
|
|
20830
|
+
let renderedRef2 = renderElementRef$1(htmlElement, contextForChildren);
|
|
20831
|
+
return e2(
|
|
20832
|
+
htmlElement.rawTagName,
|
|
20833
|
+
attributes22,
|
|
20834
|
+
htmlStringChild,
|
|
20835
|
+
renderedRef2,
|
|
20836
|
+
newContext.indent
|
|
20837
|
+
);
|
|
20838
|
+
}
|
|
20756
20839
|
let childIndent = contextForChildren.indent.child();
|
|
20757
20840
|
if (childNodes.length === 1 && childNodes[0].nodeType === NodeType.TEXT_NODE)
|
|
20758
20841
|
childIndent = childIndent.noFirstLineBreak();
|
|
@@ -21347,7 +21430,7 @@ ${Indent.forceIndent(code, 4)},
|
|
|
21347
21430
|
funcRepository)`
|
|
21348
21431
|
);
|
|
21349
21432
|
}
|
|
21350
|
-
const { renderedRefsManager
|
|
21433
|
+
const { renderedRefsManager } = renderReferenceManager(
|
|
21351
21434
|
renderedRoot.refs,
|
|
21352
21435
|
ReferenceManagerTarget.element
|
|
21353
21436
|
);
|
|
@@ -22273,8 +22356,9 @@ ${indent.firstLine}}`,
|
|
|
22273
22356
|
);
|
|
22274
22357
|
const closeTag = w(itemIndent, `'</${element.rawTagName}>'`);
|
|
22275
22358
|
const itemBody = mergeServerFragments([openTag, coordinateW, children, closeTag]);
|
|
22359
|
+
const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
|
|
22276
22360
|
return new RenderFragment(
|
|
22277
|
-
`${indent.firstLine}for (const ${forEachVariables.currentVar} of ${
|
|
22361
|
+
`${indent.firstLine}for (const ${forEachVariables.currentVar} of ${safeArrayExpr}) {
|
|
22278
22362
|
${itemBody.rendered}
|
|
22279
22363
|
${indent.firstLine}}`,
|
|
22280
22364
|
itemBody.imports,
|
|
@@ -22284,7 +22368,7 @@ ${indent.firstLine}}`,
|
|
|
22284
22368
|
if (isSlowForEach(element)) {
|
|
22285
22369
|
const slowForEachInfo = getSlowForEachInfo(element);
|
|
22286
22370
|
if (slowForEachInfo) {
|
|
22287
|
-
const { arrayName, jayIndex
|
|
22371
|
+
const { arrayName, jayIndex } = slowForEachInfo;
|
|
22288
22372
|
const slowValidated = validateSlowForEachAccessor(arrayName, variables);
|
|
22289
22373
|
if (isValidationError(slowValidated))
|
|
22290
22374
|
return slowValidated;
|
|
@@ -22337,7 +22421,7 @@ function renderServerHeadlessInstance(element, context, contractName) {
|
|
|
22337
22421
|
const coordResult = extractHeadlessCoordinate(element, contractName);
|
|
22338
22422
|
if (isValidationError(coordResult))
|
|
22339
22423
|
return coordResult;
|
|
22340
|
-
const { instanceCoord,
|
|
22424
|
+
const { instanceCoord, coordinateSuffix } = coordResult;
|
|
22341
22425
|
let instanceKeyExpr;
|
|
22342
22426
|
if (context.insideForEach) {
|
|
22343
22427
|
const trackByKeys = Object.keys(context.varMappings);
|
|
@@ -22555,8 +22639,9 @@ function renderServerForEachAsString(element, context) {
|
|
|
22555
22639
|
variables: forEachVariables
|
|
22556
22640
|
};
|
|
22557
22641
|
const itemContent = renderServerElementAsString(element, itemContext);
|
|
22642
|
+
const safeArrayExpr = arrayExpr.includes("?.") ? `(${arrayExpr} ?? [])` : arrayExpr;
|
|
22558
22643
|
return new RenderFragment(
|
|
22559
|
-
`${
|
|
22644
|
+
`${safeArrayExpr}.map((${forEachVariables.currentVar}) => ${itemContent.rendered}).join('')`,
|
|
22560
22645
|
itemContent.imports,
|
|
22561
22646
|
itemContent.validations
|
|
22562
22647
|
);
|
|
@@ -22776,14 +22861,24 @@ function renderServerElementContent(element, context, options) {
|
|
|
22776
22861
|
}
|
|
22777
22862
|
if (isVoid)
|
|
22778
22863
|
return mergeServerFragments(parts);
|
|
22864
|
+
const htmlStringBindings = findHtmlStringBindings(childNodes, variables);
|
|
22865
|
+
if (htmlStringBindings.length > 0 && !dynamicTextFragment) {
|
|
22866
|
+
return new RenderFragment("", Imports.none(), [
|
|
22867
|
+
`html-string binding {${htmlStringBindings[0]}} must be the sole child of its parent element, not mixed with sibling elements`
|
|
22868
|
+
]);
|
|
22869
|
+
}
|
|
22779
22870
|
if (dynamicTextFragment) {
|
|
22780
|
-
|
|
22781
|
-
w(
|
|
22782
|
-
|
|
22783
|
-
|
|
22784
|
-
|
|
22785
|
-
|
|
22786
|
-
|
|
22871
|
+
if (htmlStringBindings.length > 0) {
|
|
22872
|
+
parts.push(w(indent, `String(${dynamicTextFragment.rendered})`));
|
|
22873
|
+
} else {
|
|
22874
|
+
parts.push(
|
|
22875
|
+
w(
|
|
22876
|
+
indent,
|
|
22877
|
+
`escapeHtml(String(${dynamicTextFragment.rendered}))`,
|
|
22878
|
+
Imports.for(Import.escapeHtml)
|
|
22879
|
+
)
|
|
22880
|
+
);
|
|
22881
|
+
}
|
|
22787
22882
|
} else {
|
|
22788
22883
|
const childContext = {
|
|
22789
22884
|
...context,
|
|
@@ -396,11 +396,12 @@ tags:
|
|
|
396
396
|
|
|
397
397
|
### Basic Types
|
|
398
398
|
|
|
399
|
-
| Type
|
|
400
|
-
|
|
|
401
|
-
| `string`
|
|
402
|
-
| `
|
|
403
|
-
| `
|
|
399
|
+
| Type | Example | Description |
|
|
400
|
+
| ------------- | ----------------------- | ------------------------------------------------------------- |
|
|
401
|
+
| `string` | `dataType: string` | Text values |
|
|
402
|
+
| `html-string` | `dataType: html-string` | HTML content (rich text, CMS output) — rendered via innerHTML |
|
|
403
|
+
| `number` | `dataType: number` | Numeric values |
|
|
404
|
+
| `boolean` | `dataType: boolean` | True/false values |
|
|
404
405
|
|
|
405
406
|
### Enum Types
|
|
406
407
|
|
package/docs/jay-html-docs.md
CHANGED
|
@@ -15,6 +15,7 @@ Each property in the YAML becomes a property of the component's view state, supp
|
|
|
15
15
|
| Type | Example | Description |
|
|
16
16
|
| --------------- | ---------------------------------------------------------------------------- | ------------------------------------ |
|
|
17
17
|
| `string` | `text: string` | Text values |
|
|
18
|
+
| `html-string` | `richContent: html-string` | HTML content (rich text, CMS output) |
|
|
18
19
|
| `number` | `count: number` | Numeric values |
|
|
19
20
|
| `boolean` | `isVisible: boolean` | True/false values |
|
|
20
21
|
| `object` | <code>user: </br> name: string</br> age: number</code> | Nested object structures |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/compiler-jay-html",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,14 +34,15 @@
|
|
|
34
34
|
},
|
|
35
35
|
"author": "",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@jay-framework/compiler-analyze-exported-types": "^0.
|
|
38
|
-
"@jay-framework/compiler-shared": "^0.
|
|
39
|
-
"@jay-framework/component": "^0.
|
|
40
|
-
"@jay-framework/logger": "^0.
|
|
41
|
-
"@jay-framework/runtime": "^0.
|
|
42
|
-
"@jay-framework/secure": "^0.
|
|
37
|
+
"@jay-framework/compiler-analyze-exported-types": "^0.17.0",
|
|
38
|
+
"@jay-framework/compiler-shared": "^0.17.0",
|
|
39
|
+
"@jay-framework/component": "^0.17.0",
|
|
40
|
+
"@jay-framework/logger": "^0.17.0",
|
|
41
|
+
"@jay-framework/runtime": "^0.17.0",
|
|
42
|
+
"@jay-framework/secure": "^0.17.0",
|
|
43
43
|
"@types/js-yaml": "^4.0.9",
|
|
44
44
|
"change-case": "^4.1.2",
|
|
45
|
+
"he": "^1.2.0",
|
|
45
46
|
"js-yaml": "^4.1.0",
|
|
46
47
|
"node-html-parser": "^6.1.12",
|
|
47
48
|
"pegjs": "^0.10.0",
|
|
@@ -51,8 +52,8 @@
|
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@caiogondim/strip-margin": "^1.0.0",
|
|
54
|
-
"@jay-framework/4-react": "^0.
|
|
55
|
-
"@jay-framework/dev-environment": "^0.
|
|
55
|
+
"@jay-framework/4-react": "^0.17.0",
|
|
56
|
+
"@jay-framework/dev-environment": "^0.17.0",
|
|
56
57
|
"@testing-library/jest-dom": "^6.2.0",
|
|
57
58
|
"@types/js-beautify": "^1",
|
|
58
59
|
"@types/node": "^20.11.5",
|