@reckona/mreact-compiler 0.0.137 → 0.0.139

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 +1 @@
1
- {"version":3,"file":"oxc-node-utils.d.ts","sourceRoot":"","sources":["../src/oxc-node-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAEnD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAQtF;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,cAAc,GAAG,SAAS,CAkB5B;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEtF"}
1
+ {"version":3,"file":"oxc-node-utils.d.ts","sourceRoot":"","sources":["../src/oxc-node-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAEnD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAQtF;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,cAAc,GAAG,SAAS,CAY5B;AAoDD,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEtF"}
@@ -1,3 +1,5 @@
1
+ const lineStartCache = new Map();
2
+ const lineStartCacheLimit = 128;
1
3
  export function readObject(value) {
2
4
  return typeof value === "object" && value !== null ? value : {};
3
5
  }
@@ -28,18 +30,50 @@ export function getOxcLocationFromOffset(code, start) {
28
30
  if (!Number.isInteger(start) || start < 0 || start > code.length) {
29
31
  return undefined;
30
32
  }
31
- let line = 1;
32
- let column = 1;
33
- for (let index = 0; index < start; index += 1) {
33
+ const lineStarts = getLineStarts(code);
34
+ const lineIndex = findLineStartIndex(lineStarts, start);
35
+ return {
36
+ line: lineIndex + 1,
37
+ column: start - (lineStarts[lineIndex] ?? 0) + 1,
38
+ };
39
+ }
40
+ function getLineStarts(code) {
41
+ const cached = lineStartCache.get(code);
42
+ if (cached !== undefined) {
43
+ return cached;
44
+ }
45
+ const starts = [0];
46
+ for (let index = 0; index < code.length; index += 1) {
34
47
  if (code[index] === "\n") {
35
- line += 1;
36
- column = 1;
48
+ starts.push(index + 1);
49
+ }
50
+ }
51
+ rememberLineStarts(code, starts);
52
+ return starts;
53
+ }
54
+ function rememberLineStarts(code, starts) {
55
+ if (lineStartCache.size >= lineStartCacheLimit) {
56
+ const first = lineStartCache.keys().next().value;
57
+ if (first !== undefined) {
58
+ lineStartCache.delete(first);
59
+ }
60
+ }
61
+ lineStartCache.set(code, starts);
62
+ }
63
+ function findLineStartIndex(lineStarts, offset) {
64
+ let low = 0;
65
+ let high = lineStarts.length - 1;
66
+ while (low <= high) {
67
+ const middle = Math.floor((low + high) / 2);
68
+ const lineStart = lineStarts[middle] ?? 0;
69
+ if (lineStart <= offset) {
70
+ low = middle + 1;
37
71
  }
38
72
  else {
39
- column += 1;
73
+ high = middle - 1;
40
74
  }
41
75
  }
42
- return { line, column };
76
+ return Math.max(0, low - 1);
43
77
  }
44
78
  export function arraysEqual(left, right) {
45
79
  return left.length === right.length && left.every((value, index) => value === right[index]);
@@ -1 +1 @@
1
- {"version":3,"file":"oxc-node-utils.js","sourceRoot":"","sources":["../src/oxc-node-utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAE,KAAiC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,IAAa;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;QACvE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC;QACtC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,UAAmC;IAEnC,IAAI,OAAO,GAAG,UAAU,CAAC;IAEzB,OAAO,OAAO,CAAC,IAAI,KAAK,yBAAyB,EAAE,CAAC;QAClD,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAa;IACxD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAErC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,wBAAwB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,IAAY,EACZ,KAAa;IAEb,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACjE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,CAAC;YACV,MAAM,GAAG,CAAC,CAAC;QACb,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAuB,EAAE,KAAwB;IAC3E,OAAO,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9F,CAAC","sourcesContent":["import type { SourceLocation } from \"./types.js\";\n\nexport function readObject(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nexport function readArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nexport function readSource(code: string, node: unknown): string {\n const object = readObject(node);\n return typeof object.start === \"number\" && typeof object.end === \"number\"\n ? code.slice(object.start, object.end)\n : \"\";\n}\n\nexport function unwrapOxcParentheses(\n expression: Record<string, unknown>,\n): Record<string, unknown> {\n let current = expression;\n\n while (current.type === \"ParenthesizedExpression\") {\n current = readObject(current.expression);\n }\n\n return current;\n}\n\nexport function getOxcLocation(code: string, node: unknown): SourceLocation | undefined {\n const start = readObject(node).start;\n\n if (typeof start !== \"number\") {\n return undefined;\n }\n\n return getOxcLocationFromOffset(code, start);\n}\n\nexport function getOxcLocationFromOffset(\n code: string,\n start: number,\n): SourceLocation | undefined {\n if (!Number.isInteger(start) || start < 0 || start > code.length) {\n return undefined;\n }\n\n let line = 1;\n let column = 1;\n\n for (let index = 0; index < start; index += 1) {\n if (code[index] === \"\\n\") {\n line += 1;\n column = 1;\n } else {\n column += 1;\n }\n }\n\n return { line, column };\n}\n\nexport function arraysEqual(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
1
+ {"version":3,"file":"oxc-node-utils.js","sourceRoot":"","sources":["../src/oxc-node-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SourceLocation } from \"./types.js\";\n\nconst lineStartCache = new Map<string, readonly number[]>();\nconst lineStartCacheLimit = 128;\n\nexport function readObject(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n\nexport function readArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nexport function readSource(code: string, node: unknown): string {\n const object = readObject(node);\n return typeof object.start === \"number\" && typeof object.end === \"number\"\n ? code.slice(object.start, object.end)\n : \"\";\n}\n\nexport function unwrapOxcParentheses(\n expression: Record<string, unknown>,\n): Record<string, unknown> {\n let current = expression;\n\n while (current.type === \"ParenthesizedExpression\") {\n current = readObject(current.expression);\n }\n\n return current;\n}\n\nexport function getOxcLocation(code: string, node: unknown): SourceLocation | undefined {\n const start = readObject(node).start;\n\n if (typeof start !== \"number\") {\n return undefined;\n }\n\n return getOxcLocationFromOffset(code, start);\n}\n\nexport function getOxcLocationFromOffset(\n code: string,\n start: number,\n): SourceLocation | undefined {\n if (!Number.isInteger(start) || start < 0 || start > code.length) {\n return undefined;\n }\n\n const lineStarts = getLineStarts(code);\n const lineIndex = findLineStartIndex(lineStarts, start);\n\n return {\n line: lineIndex + 1,\n column: start - (lineStarts[lineIndex] ?? 0) + 1,\n };\n}\n\nfunction getLineStarts(code: string): readonly number[] {\n const cached = lineStartCache.get(code);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const starts = [0];\n\n for (let index = 0; index < code.length; index += 1) {\n if (code[index] === \"\\n\") {\n starts.push(index + 1);\n }\n }\n\n rememberLineStarts(code, starts);\n\n return starts;\n}\n\nfunction rememberLineStarts(code: string, starts: readonly number[]): void {\n if (lineStartCache.size >= lineStartCacheLimit) {\n const first = lineStartCache.keys().next().value;\n\n if (first !== undefined) {\n lineStartCache.delete(first);\n }\n }\n\n lineStartCache.set(code, starts);\n}\n\nfunction findLineStartIndex(lineStarts: readonly number[], offset: number): number {\n let low = 0;\n let high = lineStarts.length - 1;\n\n while (low <= high) {\n const middle = Math.floor((low + high) / 2);\n const lineStart = lineStarts[middle] ?? 0;\n\n if (lineStart <= offset) {\n low = middle + 1;\n } else {\n high = middle - 1;\n }\n }\n\n return Math.max(0, low - 1);\n}\n\nexport function arraysEqual(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { JsxNodeIr } from "./ir.js";
2
2
  export declare const oxcServerStringReactNodeRenderHelperPlaceholder = "__mreactRenderReactNodeToString";
3
+ export declare function setOxcServerStringUrlSafeHelperName(name: string): void;
3
4
  export declare function emitOxcServerStringChildren(children: readonly JsxNodeIr[]): string;
4
5
  export declare function emitOxcCompatObjectChildren(children: readonly JsxNodeIr[]): string;
5
6
  //# sourceMappingURL=oxc-runtime-emit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oxc-runtime-emit.d.ts","sourceRoot":"","sources":["../src/oxc-runtime-emit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,SAAS,CAAC;AAIvE,eAAO,MAAM,+CAA+C,oCACzB,CAAC;AAEpC,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAMlF;AAwID,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAUlF"}
1
+ {"version":3,"file":"oxc-runtime-emit.d.ts","sourceRoot":"","sources":["../src/oxc-runtime-emit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,SAAS,CAAC;AAUvE,eAAO,MAAM,+CAA+C,oCACzB,CAAC;AAIpC,wBAAgB,mCAAmC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAMlF;AAkLD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAUlF"}
@@ -1,6 +1,10 @@
1
- import { isVoidHtmlElement } from "./emit-server-shared.js";
1
+ import { htmlAttributeName, isDangerousHtmlAttribute, isStaticUrlValueUnsafe, isUrlAttribute, isVoidHtmlElement, } from "./emit-server-shared.js";
2
2
  import { escapeHtmlAttribute } from "@reckona/mreact-shared/html-escape";
3
3
  export const oxcServerStringReactNodeRenderHelperPlaceholder = "__mreactRenderReactNodeToString";
4
+ let currentOxcServerStringUrlSafeHelperName = "_urlAttrSafe";
5
+ export function setOxcServerStringUrlSafeHelperName(name) {
6
+ currentOxcServerStringUrlSafeHelperName = name;
7
+ }
4
8
  export function emitOxcServerStringChildren(children) {
5
9
  if (children.length === 0) {
6
10
  return '""';
@@ -38,7 +42,9 @@ function emitOxcServerStringNode(node) {
38
42
  if (node.kind === "async-boundary") {
39
43
  return '""';
40
44
  }
41
- const attrs = node.attributes.map(emitOxcServerAttribute).join(" + ");
45
+ const attrs = node.attributes
46
+ .map((attr) => emitOxcServerAttribute(node.tagName, attr))
47
+ .join(" + ");
42
48
  const open = attrs === ""
43
49
  ? JSON.stringify(`<${node.tagName}>`)
44
50
  : `${JSON.stringify(`<${node.tagName}`)} + ${attrs} + ">"`;
@@ -62,15 +68,45 @@ function emitOxcServerComponentProps(props, children) {
62
68
  }
63
69
  return `{ ${entries.join(", ")} }`;
64
70
  }
65
- function emitOxcServerAttribute(attr) {
71
+ function emitOxcServerAttribute(tagName, attr) {
72
+ if (attr.kind === "spread-attr" || attr.kind === "event") {
73
+ return '""';
74
+ }
75
+ if (attr.name === "key" || attr.name === "dangerouslySetInnerHTML") {
76
+ return '""';
77
+ }
78
+ const htmlName = htmlAttributeNameForElement(tagName, attr.name);
66
79
  if (attr.kind === "static-attr") {
67
- return JSON.stringify(` ${attr.name}="${escapeHtmlAttribute(attr.value)}"`);
80
+ if (isUrlAttribute(htmlName) && isStaticUrlValueUnsafe(htmlName, attr.value)) {
81
+ return '""';
82
+ }
83
+ if (isDangerousHtmlAttribute(htmlName)) {
84
+ return '""';
85
+ }
86
+ return JSON.stringify(` ${htmlName}="${escapeHtmlAttribute(attr.value)}"`);
68
87
  }
69
88
  if (attr.kind === "dynamic-attr") {
70
- return `${JSON.stringify(` ${attr.name}="`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('"')}`;
89
+ if (isDangerousHtmlAttribute(htmlName)) {
90
+ return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(_value.__html) + ${JSON.stringify('"')}; return ""; })()`;
91
+ }
92
+ if (isUrlAttribute(htmlName)) {
93
+ return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; const _checked = ${currentOxcServerStringUrlSafeHelperName}(${JSON.stringify(htmlName)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(_checked) + ${JSON.stringify('"')}; })()`;
94
+ }
95
+ return `${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('"')}`;
71
96
  }
72
97
  return '""';
73
98
  }
99
+ function htmlAttributeNameForElement(tagName, name) {
100
+ if (tagName === "input") {
101
+ if (name === "defaultValue") {
102
+ return "value";
103
+ }
104
+ if (name === "defaultChecked") {
105
+ return "checked";
106
+ }
107
+ }
108
+ return htmlAttributeName(name);
109
+ }
74
110
  function emitOxcCompatObjectNode(node) {
75
111
  if (node.kind === "text") {
76
112
  return JSON.stringify(node.value);
@@ -1 +1 @@
1
- {"version":3,"file":"oxc-runtime-emit.js","sourceRoot":"","sources":["../src/oxc-runtime-emit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AttributeIr, ComponentPropIr, JsxNodeIr } from \"./ir.js\";\nimport { isVoidHtmlElement } from \"./emit-server-shared.js\";\nimport { escapeHtmlAttribute } from \"@reckona/mreact-shared/html-escape\";\n\nexport const oxcServerStringReactNodeRenderHelperPlaceholder =\n \"__mreactRenderReactNodeToString\";\n\nexport function emitOxcServerStringChildren(children: readonly JsxNodeIr[]): string {\n if (children.length === 0) {\n return '\"\"';\n }\n\n return children.map(emitOxcServerStringNode).join(\" + \");\n}\n\nfunction emitOxcServerStringNode(node: JsxNodeIr): string {\n if (node.kind === \"text\") {\n return JSON.stringify(node.value);\n }\n\n if (node.kind === \"expr\") {\n return `_escapeHtml(${node.code})`;\n }\n\n if (node.kind === \"conditional\") {\n const whenTrue = emitOxcServerStringChildren(node.whenTrue);\n const whenFalse = emitOxcServerStringChildren(node.whenFalse);\n\n return node.conditionValueName === undefined\n ? `((${node.conditionCode}) ? ${whenTrue} : ${whenFalse})`\n : `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;\n }\n\n if (node.kind === \"list\") {\n const parameters = emitOxcListParameters(node);\n return `(${node.itemsCode}).map((${parameters}) => ${emitOxcServerStringChildren(node.children)}).join(\"\")`;\n }\n\n if (node.kind === \"fragment\") {\n return emitOxcServerStringChildren(node.children);\n }\n\n if (node.kind === \"component\") {\n const props = emitOxcServerComponentProps(node.props, node.children);\n if (node.runtime === \"compat\") {\n return `${oxcServerStringReactNodeRenderHelperPlaceholder}(${node.name}, ${props})`;\n }\n return `${node.name}(${props})`;\n }\n\n if (node.kind === \"async-boundary\") {\n return '\"\"';\n }\n\n const attrs = node.attributes.map(emitOxcServerAttribute).join(\" + \");\n const open =\n attrs === \"\"\n ? JSON.stringify(`<${node.tagName}>`)\n : `${JSON.stringify(`<${node.tagName}`)} + ${attrs} + \">\"`;\n if (isVoidHtmlElement(node.tagName)) {\n return open;\n }\n\n return `${open} + ${emitOxcServerStringChildren(node.children)} + ${JSON.stringify(`</${node.tagName}>`)}`;\n}\n\nfunction emitOxcServerComponentProps(\n props: readonly ComponentPropIr[],\n children: readonly JsxNodeIr[],\n): string {\n const entries = props.map((prop) => {\n if (prop.kind === \"spread-prop\") {\n return `...(${prop.code})`;\n }\n\n if (prop.kind === \"render-prop\") {\n return `${emitOxcCompatObjectPropName(prop.name)}: ${emitOxcServerStringChildren(prop.children)}`;\n }\n\n return `${emitOxcCompatObjectPropName(prop.name)}: (${prop.code})`;\n });\n\n if (children.length > 0) {\n entries.push(`children: ${emitOxcServerStringChildren(children)}`);\n }\n\n return `{ ${entries.join(\", \")} }`;\n}\n\nfunction emitOxcServerAttribute(attr: AttributeIr): string {\n if (attr.kind === \"static-attr\") {\n return JSON.stringify(` ${attr.name}=\"${escapeHtmlAttribute(attr.value)}\"`);\n }\n\n if (attr.kind === \"dynamic-attr\") {\n return `${JSON.stringify(` ${attr.name}=\"`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('\"')}`;\n }\n\n return '\"\"';\n}\n\nfunction emitOxcCompatObjectNode(node: JsxNodeIr): string {\n if (node.kind === \"text\") {\n return JSON.stringify(node.value);\n }\n\n if (node.kind === \"expr\") {\n return `(${node.code})`;\n }\n\n if (node.kind === \"conditional\") {\n const whenTrue = emitOxcCompatObjectChildren(node.whenTrue);\n const whenFalse = emitOxcCompatObjectChildren(node.whenFalse);\n\n return node.conditionValueName === undefined\n ? `(${node.conditionCode}) ? ${whenTrue} : ${whenFalse}`\n : `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;\n }\n\n if (node.kind === \"list\") {\n const parameters = emitOxcListParameters(node);\n return `(${node.itemsCode}).map((${parameters}) => ${emitOxcCompatObjectChildren(node.children)})`;\n }\n\n if (node.kind === \"fragment\") {\n return emitOxcCompatObjectElement('Symbol.for(\"react.fragment\")', [], node.children);\n }\n\n if (node.kind === \"component\") {\n return emitOxcCompatObjectElement(\n node.name,\n node.props.map(emitOxcCompatObjectComponentProp),\n node.children,\n node.keyCode,\n );\n }\n\n if (node.kind === \"async-boundary\") {\n return \"null\";\n }\n\n return emitOxcCompatObjectElement(\n JSON.stringify(node.tagName),\n node.attributes.map(emitOxcCompatObjectAttribute),\n node.children,\n node.keyCode,\n );\n}\n\nexport function emitOxcCompatObjectChildren(children: readonly JsxNodeIr[]): string {\n if (children.length === 0) {\n return \"null\";\n }\n\n if (children.length === 1) {\n return emitOxcCompatObjectNode(children[0] as JsxNodeIr);\n }\n\n return `[${children.map(emitOxcCompatObjectNode).join(\", \")}]`;\n}\n\nfunction emitOxcCompatObjectElement(\n typeCode: string,\n propEntries: readonly string[],\n children: readonly JsxNodeIr[],\n explicitKeyCode?: string,\n): string {\n const entries = [...propEntries];\n\n if (children.length > 0) {\n entries.push(`children: ${emitOxcCompatObjectChildren(children)}`);\n }\n\n const keyExpression =\n explicitKeyCode === undefined\n ? \"_props.key === undefined ? null : String(_props.key)\"\n : `String(${explicitKeyCode})`;\n\n return [\n \"(() => {\",\n ` const _props = { ${entries.join(\", \")} };`,\n ` const _key = ${keyExpression};`,\n \" const _ref = _props.ref ?? null;\",\n \" delete _props.key;\",\n \" delete _props.ref;\",\n ' return { $$typeof: Symbol.for(\"react.transitional.element\"),',\n ` type: ${typeCode},`,\n \" key: _key,\",\n \" ref: _ref,\",\n \" props: _props };\",\n \"})()\",\n ].join(\"\\n\");\n}\n\nfunction emitOxcListParameters(node: Extract<JsxNodeIr, { kind: \"list\" }>): string {\n return [node.itemName, node.indexName, node.arrayName]\n .filter((name): name is string => name !== undefined)\n .join(\", \");\n}\n\nfunction emitOxcCompatObjectAttribute(attr: AttributeIr): string {\n if (attr.kind === \"spread-attr\") {\n return `...(${attr.code})`;\n }\n\n if (attr.kind === \"static-attr\") {\n return `${emitOxcCompatObjectPropName(attr.name)}: ${JSON.stringify(attr.value)}`;\n }\n\n if (attr.kind === \"dynamic-attr\") {\n return `${emitOxcCompatObjectPropName(attr.name)}: (${attr.code})`;\n }\n\n return `${emitOxcCompatObjectPropName(attr.name)}: ${attr.code}`;\n}\n\nfunction emitOxcCompatObjectComponentProp(prop: ComponentPropIr): string {\n if (prop.kind === \"spread-prop\") {\n return `...(${prop.code})`;\n }\n\n if (prop.kind === \"render-prop\") {\n return `${emitOxcCompatObjectPropName(prop.name)}: ${emitOxcCompatObjectChildren(prop.children)}`;\n }\n\n return `${emitOxcCompatObjectPropName(prop.name)}: (${prop.code})`;\n}\n\nfunction emitOxcCompatObjectPropName(name: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(name) ? name : JSON.stringify(name);\n}\n"]}
1
+ {"version":3,"file":"oxc-runtime-emit.js","sourceRoot":"","sources":["../src/oxc-runtime-emit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AttributeIr, ComponentPropIr, JsxNodeIr } from \"./ir.js\";\nimport {\n htmlAttributeName,\n isDangerousHtmlAttribute,\n isStaticUrlValueUnsafe,\n isUrlAttribute,\n isVoidHtmlElement,\n} from \"./emit-server-shared.js\";\nimport { escapeHtmlAttribute } from \"@reckona/mreact-shared/html-escape\";\n\nexport const oxcServerStringReactNodeRenderHelperPlaceholder =\n \"__mreactRenderReactNodeToString\";\n\nlet currentOxcServerStringUrlSafeHelperName = \"_urlAttrSafe\";\n\nexport function setOxcServerStringUrlSafeHelperName(name: string): void {\n currentOxcServerStringUrlSafeHelperName = name;\n}\n\nexport function emitOxcServerStringChildren(children: readonly JsxNodeIr[]): string {\n if (children.length === 0) {\n return '\"\"';\n }\n\n return children.map(emitOxcServerStringNode).join(\" + \");\n}\n\nfunction emitOxcServerStringNode(node: JsxNodeIr): string {\n if (node.kind === \"text\") {\n return JSON.stringify(node.value);\n }\n\n if (node.kind === \"expr\") {\n return `_escapeHtml(${node.code})`;\n }\n\n if (node.kind === \"conditional\") {\n const whenTrue = emitOxcServerStringChildren(node.whenTrue);\n const whenFalse = emitOxcServerStringChildren(node.whenFalse);\n\n return node.conditionValueName === undefined\n ? `((${node.conditionCode}) ? ${whenTrue} : ${whenFalse})`\n : `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;\n }\n\n if (node.kind === \"list\") {\n const parameters = emitOxcListParameters(node);\n return `(${node.itemsCode}).map((${parameters}) => ${emitOxcServerStringChildren(node.children)}).join(\"\")`;\n }\n\n if (node.kind === \"fragment\") {\n return emitOxcServerStringChildren(node.children);\n }\n\n if (node.kind === \"component\") {\n const props = emitOxcServerComponentProps(node.props, node.children);\n if (node.runtime === \"compat\") {\n return `${oxcServerStringReactNodeRenderHelperPlaceholder}(${node.name}, ${props})`;\n }\n return `${node.name}(${props})`;\n }\n\n if (node.kind === \"async-boundary\") {\n return '\"\"';\n }\n\n const attrs = node.attributes\n .map((attr) => emitOxcServerAttribute(node.tagName, attr))\n .join(\" + \");\n const open =\n attrs === \"\"\n ? JSON.stringify(`<${node.tagName}>`)\n : `${JSON.stringify(`<${node.tagName}`)} + ${attrs} + \">\"`;\n if (isVoidHtmlElement(node.tagName)) {\n return open;\n }\n\n return `${open} + ${emitOxcServerStringChildren(node.children)} + ${JSON.stringify(`</${node.tagName}>`)}`;\n}\n\nfunction emitOxcServerComponentProps(\n props: readonly ComponentPropIr[],\n children: readonly JsxNodeIr[],\n): string {\n const entries = props.map((prop) => {\n if (prop.kind === \"spread-prop\") {\n return `...(${prop.code})`;\n }\n\n if (prop.kind === \"render-prop\") {\n return `${emitOxcCompatObjectPropName(prop.name)}: ${emitOxcServerStringChildren(prop.children)}`;\n }\n\n return `${emitOxcCompatObjectPropName(prop.name)}: (${prop.code})`;\n });\n\n if (children.length > 0) {\n entries.push(`children: ${emitOxcServerStringChildren(children)}`);\n }\n\n return `{ ${entries.join(\", \")} }`;\n}\n\nfunction emitOxcServerAttribute(tagName: string, attr: AttributeIr): string {\n if (attr.kind === \"spread-attr\" || attr.kind === \"event\") {\n return '\"\"';\n }\n\n if (attr.name === \"key\" || attr.name === \"dangerouslySetInnerHTML\") {\n return '\"\"';\n }\n\n const htmlName = htmlAttributeNameForElement(tagName, attr.name);\n\n if (attr.kind === \"static-attr\") {\n if (isUrlAttribute(htmlName) && isStaticUrlValueUnsafe(htmlName, attr.value)) {\n return '\"\"';\n }\n\n if (isDangerousHtmlAttribute(htmlName)) {\n return '\"\"';\n }\n\n return JSON.stringify(` ${htmlName}=\"${escapeHtmlAttribute(attr.value)}\"`);\n }\n\n if (attr.kind === \"dynamic-attr\") {\n if (isDangerousHtmlAttribute(htmlName)) {\n return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return \"\"; if (typeof _value === \"object\" && _value !== null && typeof _value.__html === \"string\") return ${JSON.stringify(` ${htmlName}=\"`)} + _escapeHtml(_value.__html) + ${JSON.stringify('\"')}; return \"\"; })()`;\n }\n\n if (isUrlAttribute(htmlName)) {\n return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return \"\"; const _checked = ${currentOxcServerStringUrlSafeHelperName}(${JSON.stringify(htmlName)}, _value === true ? \"\" : _value); return _checked === undefined ? \"\" : ${JSON.stringify(` ${htmlName}=\"`)} + _escapeHtml(_checked) + ${JSON.stringify('\"')}; })()`;\n }\n\n return `${JSON.stringify(` ${htmlName}=\"`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('\"')}`;\n }\n\n return '\"\"';\n}\n\nfunction htmlAttributeNameForElement(tagName: string, name: string): string {\n if (tagName === \"input\") {\n if (name === \"defaultValue\") {\n return \"value\";\n }\n\n if (name === \"defaultChecked\") {\n return \"checked\";\n }\n }\n\n return htmlAttributeName(name);\n}\n\nfunction emitOxcCompatObjectNode(node: JsxNodeIr): string {\n if (node.kind === \"text\") {\n return JSON.stringify(node.value);\n }\n\n if (node.kind === \"expr\") {\n return `(${node.code})`;\n }\n\n if (node.kind === \"conditional\") {\n const whenTrue = emitOxcCompatObjectChildren(node.whenTrue);\n const whenFalse = emitOxcCompatObjectChildren(node.whenFalse);\n\n return node.conditionValueName === undefined\n ? `(${node.conditionCode}) ? ${whenTrue} : ${whenFalse}`\n : `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;\n }\n\n if (node.kind === \"list\") {\n const parameters = emitOxcListParameters(node);\n return `(${node.itemsCode}).map((${parameters}) => ${emitOxcCompatObjectChildren(node.children)})`;\n }\n\n if (node.kind === \"fragment\") {\n return emitOxcCompatObjectElement('Symbol.for(\"react.fragment\")', [], node.children);\n }\n\n if (node.kind === \"component\") {\n return emitOxcCompatObjectElement(\n node.name,\n node.props.map(emitOxcCompatObjectComponentProp),\n node.children,\n node.keyCode,\n );\n }\n\n if (node.kind === \"async-boundary\") {\n return \"null\";\n }\n\n return emitOxcCompatObjectElement(\n JSON.stringify(node.tagName),\n node.attributes.map(emitOxcCompatObjectAttribute),\n node.children,\n node.keyCode,\n );\n}\n\nexport function emitOxcCompatObjectChildren(children: readonly JsxNodeIr[]): string {\n if (children.length === 0) {\n return \"null\";\n }\n\n if (children.length === 1) {\n return emitOxcCompatObjectNode(children[0] as JsxNodeIr);\n }\n\n return `[${children.map(emitOxcCompatObjectNode).join(\", \")}]`;\n}\n\nfunction emitOxcCompatObjectElement(\n typeCode: string,\n propEntries: readonly string[],\n children: readonly JsxNodeIr[],\n explicitKeyCode?: string,\n): string {\n const entries = [...propEntries];\n\n if (children.length > 0) {\n entries.push(`children: ${emitOxcCompatObjectChildren(children)}`);\n }\n\n const keyExpression =\n explicitKeyCode === undefined\n ? \"_props.key === undefined ? null : String(_props.key)\"\n : `String(${explicitKeyCode})`;\n\n return [\n \"(() => {\",\n ` const _props = { ${entries.join(\", \")} };`,\n ` const _key = ${keyExpression};`,\n \" const _ref = _props.ref ?? null;\",\n \" delete _props.key;\",\n \" delete _props.ref;\",\n ' return { $$typeof: Symbol.for(\"react.transitional.element\"),',\n ` type: ${typeCode},`,\n \" key: _key,\",\n \" ref: _ref,\",\n \" props: _props };\",\n \"})()\",\n ].join(\"\\n\");\n}\n\nfunction emitOxcListParameters(node: Extract<JsxNodeIr, { kind: \"list\" }>): string {\n return [node.itemName, node.indexName, node.arrayName]\n .filter((name): name is string => name !== undefined)\n .join(\", \");\n}\n\nfunction emitOxcCompatObjectAttribute(attr: AttributeIr): string {\n if (attr.kind === \"spread-attr\") {\n return `...(${attr.code})`;\n }\n\n if (attr.kind === \"static-attr\") {\n return `${emitOxcCompatObjectPropName(attr.name)}: ${JSON.stringify(attr.value)}`;\n }\n\n if (attr.kind === \"dynamic-attr\") {\n return `${emitOxcCompatObjectPropName(attr.name)}: (${attr.code})`;\n }\n\n return `${emitOxcCompatObjectPropName(attr.name)}: ${attr.code}`;\n}\n\nfunction emitOxcCompatObjectComponentProp(prop: ComponentPropIr): string {\n if (prop.kind === \"spread-prop\") {\n return `...(${prop.code})`;\n }\n\n if (prop.kind === \"render-prop\") {\n return `${emitOxcCompatObjectPropName(prop.name)}: ${emitOxcCompatObjectChildren(prop.children)}`;\n }\n\n return `${emitOxcCompatObjectPropName(prop.name)}: (${prop.code})`;\n}\n\nfunction emitOxcCompatObjectPropName(name: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(name) ? name : JSON.stringify(name);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"oxc-transform.d.ts","sourceRoot":"","sources":["../src/oxc-transform.ts"],"names":[],"mappings":"AAEA,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoB7D;AAaD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmB1D;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoBzE"}
1
+ {"version":3,"file":"oxc-transform.d.ts","sourceRoot":"","sources":["../src/oxc-transform.ts"],"names":[],"mappings":"AAKA,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0B7D;AAyBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmB1D;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoBzE"}
@@ -1,8 +1,14 @@
1
1
  import { transformSync } from "oxc-transform";
2
+ const stripTypeScriptCache = new Map();
3
+ const stripTypeScriptCacheLimit = 512;
2
4
  export function stripTypeScriptWithOxc(source) {
3
5
  if (!needsTypeScriptStripping(source)) {
4
6
  return source.trimEnd();
5
7
  }
8
+ const cached = stripTypeScriptCache.get(source);
9
+ if (cached !== undefined) {
10
+ return cached;
11
+ }
6
12
  const result = transformSync("snippet.tsx", source, {
7
13
  lang: "tsx",
8
14
  sourceType: "module",
@@ -12,10 +18,18 @@ export function stripTypeScriptWithOxc(source) {
12
18
  onlyRemoveTypeImports: true,
13
19
  },
14
20
  });
15
- if (result.errors.length > 0) {
16
- return source.trimEnd();
21
+ const stripped = result.errors.length > 0 ? source.trimEnd() : result.code.trimEnd();
22
+ rememberStrippedTypeScript(source, stripped);
23
+ return stripped;
24
+ }
25
+ function rememberStrippedTypeScript(source, stripped) {
26
+ if (stripTypeScriptCache.size >= stripTypeScriptCacheLimit) {
27
+ const first = stripTypeScriptCache.keys().next().value;
28
+ if (first !== undefined) {
29
+ stripTypeScriptCache.delete(first);
30
+ }
17
31
  }
18
- return result.code.trimEnd();
32
+ stripTypeScriptCache.set(source, stripped);
19
33
  }
20
34
  function needsTypeScriptStripping(source) {
21
35
  return (/\bimport\s+type\b/.test(source) ||
@@ -1 +1 @@
1
- {"version":3,"file":"oxc-transform.js","sourceRoot":"","sources":["../src/oxc-transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE;QAClD,IAAI,EAAE,KAAK;QACX,UAAU,EAAE,QAAQ;QACpB,MAAM,EAAE,QAAQ;QAChB,GAAG,EAAE,UAAU;QACf,UAAU,EAAE;YACV,qBAAqB,EAAE,IAAI;SAC5B;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAc;IAC9C,OAAO,CACL,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC;QAChC,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC;QAC1C,kCAAkC,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/C,sCAAsC,CAAC,IAAI,CAAC,MAAM,CAAC;QACnD,qCAAqC,CAAC,IAAI,CAAC,MAAM,CAAC;QAClD,6CAA6C,CAAC,IAAI,CAAC,MAAM,CAAC,CAC3D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE;QAClD,IAAI,EAAE,KAAK;QACX,UAAU,EAAE,QAAQ;QACpB,MAAM,EAAE,QAAQ;QAChB,GAAG,EAAE;YACH,OAAO,EAAE,WAAW;YACpB,YAAY,EAAE,wBAAwB;SACvC;QACD,UAAU,EAAE;YACV,qBAAqB,EAAE,IAAI;SAC5B;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACnD,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,MAAc;IAC/D,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE;QAClD,IAAI,EAAE,KAAK;QACX,UAAU,EAAE,QAAQ;QACpB,MAAM,EAAE,QAAQ;QAChB,GAAG,EAAE;YACH,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,eAAe;YACvB,UAAU,EAAE,UAAU;SACvB;QACD,UAAU,EAAE;YACV,qBAAqB,EAAE,IAAI;SAC5B;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QACnD,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAC/B,CAAC","sourcesContent":["import { transformSync } from \"oxc-transform\";\n\nexport function stripTypeScriptWithOxc(source: string): string {\n if (!needsTypeScriptStripping(source)) {\n return source.trimEnd();\n }\n\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: \"preserve\",\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n if (result.errors.length > 0) {\n return source.trimEnd();\n }\n\n return result.code.trimEnd();\n}\n\nfunction needsTypeScriptStripping(source: string): boolean {\n return (\n /\\bimport\\s+type\\b/.test(source) ||\n /\\btype\\s+[A-Za-z_$][\\w$]*\\b/.test(source) ||\n /\\binterface\\s+[A-Za-z_$][\\w$]*\\b/.test(source) ||\n /\\b[A-Za-z_$][\\w$.]*\\s*<[^>\\n]+>\\s*\\(/.test(source) ||\n /\\bas\\s+(?:const|[A-Za-z_$][\\w$]*)\\b/.test(source) ||\n /:\\s*[A-Za-z_$][\\w$<>,\\s|&.[\\]?]*(?=[,)=;{])/.test(source)\n );\n}\n\nexport function transformJsxWithOxc(source: string): string {\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: {\n runtime: \"automatic\",\n importSource: \"@reckona/mreact-compat\",\n },\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n if (result.errors.length > 0 && result.code === \"\") {\n return stripTypeScriptWithOxc(source);\n }\n\n return result.code.trimEnd();\n}\n\nexport function transformJsxToCreateElementWithOxc(source: string): string {\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: {\n runtime: \"classic\",\n pragma: \"createElement\",\n pragmaFrag: \"Fragment\",\n },\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n if (result.errors.length > 0 && result.code === \"\") {\n return stripTypeScriptWithOxc(source);\n }\n\n return result.code.trimEnd();\n}\n"]}
1
+ {"version":3,"file":"oxc-transform.js","sourceRoot":"","sources":["../src/oxc-transform.ts"],"names":[],"mappings":"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","sourcesContent":["import { transformSync } from \"oxc-transform\";\n\nconst stripTypeScriptCache = new Map<string, string>();\nconst stripTypeScriptCacheLimit = 512;\n\nexport function stripTypeScriptWithOxc(source: string): string {\n if (!needsTypeScriptStripping(source)) {\n return source.trimEnd();\n }\n\n const cached = stripTypeScriptCache.get(source);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: \"preserve\",\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n const stripped = result.errors.length > 0 ? source.trimEnd() : result.code.trimEnd();\n\n rememberStrippedTypeScript(source, stripped);\n\n return stripped;\n}\n\nfunction rememberStrippedTypeScript(source: string, stripped: string): void {\n if (stripTypeScriptCache.size >= stripTypeScriptCacheLimit) {\n const first = stripTypeScriptCache.keys().next().value;\n\n if (first !== undefined) {\n stripTypeScriptCache.delete(first);\n }\n }\n\n stripTypeScriptCache.set(source, stripped);\n}\n\nfunction needsTypeScriptStripping(source: string): boolean {\n return (\n /\\bimport\\s+type\\b/.test(source) ||\n /\\btype\\s+[A-Za-z_$][\\w$]*\\b/.test(source) ||\n /\\binterface\\s+[A-Za-z_$][\\w$]*\\b/.test(source) ||\n /\\b[A-Za-z_$][\\w$.]*\\s*<[^>\\n]+>\\s*\\(/.test(source) ||\n /\\bas\\s+(?:const|[A-Za-z_$][\\w$]*)\\b/.test(source) ||\n /:\\s*[A-Za-z_$][\\w$<>,\\s|&.[\\]?]*(?=[,)=;{])/.test(source)\n );\n}\n\nexport function transformJsxWithOxc(source: string): string {\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: {\n runtime: \"automatic\",\n importSource: \"@reckona/mreact-compat\",\n },\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n if (result.errors.length > 0 && result.code === \"\") {\n return stripTypeScriptWithOxc(source);\n }\n\n return result.code.trimEnd();\n}\n\nexport function transformJsxToCreateElementWithOxc(source: string): string {\n const result = transformSync(\"snippet.tsx\", source, {\n lang: \"tsx\",\n sourceType: \"module\",\n target: \"es2022\",\n jsx: {\n runtime: \"classic\",\n pragma: \"createElement\",\n pragmaFrag: \"Fragment\",\n },\n typescript: {\n onlyRemoveTypeImports: true,\n },\n });\n\n if (result.errors.length > 0 && result.code === \"\") {\n return stripTypeScriptWithOxc(source);\n }\n\n return result.code.trimEnd();\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-compiler",
3
- "version": "0.0.137",
3
+ "version": "0.0.139",
4
4
  "description": "Compiler passes and OXC-backed JSX analysis for mreact.",
5
5
  "keywords": [
6
6
  "compiler",
@@ -50,6 +50,6 @@
50
50
  "dependencies": {
51
51
  "oxc-parser": "0.129.0",
52
52
  "oxc-transform": "0.129.0",
53
- "@reckona/mreact-shared": "0.0.137"
53
+ "@reckona/mreact-shared": "0.0.139"
54
54
  }
55
55
  }
@@ -30,6 +30,7 @@ import {
30
30
  import {
31
31
  emitOxcCompatObjectChildren,
32
32
  oxcServerStringReactNodeRenderHelperPlaceholder,
33
+ setOxcServerStringUrlSafeHelperName,
33
34
  } from "./oxc-runtime-emit.js";
34
35
 
35
36
  export interface EmitServerStreamResult {
@@ -84,6 +85,7 @@ export function emitServerStream(
84
85
  const spreadAttributesHelperName = allocateHelperName(ir, "_renderSpreadAttributes");
85
86
  const urlSafeHelperName = allocateHelperName(ir, "_urlAttrSafe");
86
87
  currentUrlSafeHelperName = urlSafeHelperName;
88
+ setOxcServerStringUrlSafeHelperName(urlSafeHelperName);
87
89
  currentClientBoundaryHelperName = clientBoundaryHelperName;
88
90
  currentSpreadAttributesHelperName = spreadAttributesHelperName;
89
91
  currentStreamNodeHelperName = streamNodeHelperName;
@@ -17,6 +17,7 @@ import {
17
17
  import {
18
18
  emitOxcCompatObjectChildren,
19
19
  oxcServerStringReactNodeRenderHelperPlaceholder,
20
+ setOxcServerStringUrlSafeHelperName,
20
21
  } from "./oxc-runtime-emit.js";
21
22
 
22
23
  export interface EmitResult {
@@ -57,6 +58,7 @@ export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitR
57
58
  const outAccumulatorName = allocateHelperName(ir, "_out");
58
59
  const urlSafeHelperName = allocateHelperName(ir, "_urlAttrSafe");
59
60
  currentUrlSafeHelperName = urlSafeHelperName;
61
+ setOxcServerStringUrlSafeHelperName(urlSafeHelperName);
60
62
  currentClientBoundaryHelperName = clientBoundaryHelperName;
61
63
  currentSpreadAttributesHelperName = spreadAttributesHelperName;
62
64
  const helper = emitEscapeHtmlHelper(escapeHelperName);
package/src/internal.ts CHANGED
@@ -1060,8 +1060,33 @@ interface Replacement {
1060
1060
  text: string;
1061
1061
  }
1062
1062
 
1063
+ const parseModuleCache = new Map<string, CompilerModuleContext>();
1064
+ const parseModuleCacheLimit = 128;
1065
+
1063
1066
  function parseModule(code: string, filename: string | undefined) {
1064
- return parseModuleContext(createCompilerModuleContext({ code, filename }));
1067
+ const cacheKey = `${filename ?? ""}\0${code}`;
1068
+ const cached = parseModuleCache.get(cacheKey);
1069
+
1070
+ if (cached !== undefined) {
1071
+ return parseModuleContext(cached);
1072
+ }
1073
+
1074
+ const parsed = createCompilerModuleContext({ code, filename });
1075
+ rememberParsedModule(cacheKey, parsed);
1076
+
1077
+ return parseModuleContext(parsed);
1078
+ }
1079
+
1080
+ function rememberParsedModule(cacheKey: string, context: CompilerModuleContext): void {
1081
+ if (parseModuleCache.size >= parseModuleCacheLimit) {
1082
+ const first = parseModuleCache.keys().next().value;
1083
+
1084
+ if (first !== undefined) {
1085
+ parseModuleCache.delete(first);
1086
+ }
1087
+ }
1088
+
1089
+ parseModuleCache.set(cacheKey, context);
1065
1090
  }
1066
1091
 
1067
1092
  function parseModuleContext(context: CompilerModuleContext): CompilerModuleContext {
@@ -1,5 +1,8 @@
1
1
  import type { SourceLocation } from "./types.js";
2
2
 
3
+ const lineStartCache = new Map<string, readonly number[]>();
4
+ const lineStartCacheLimit = 128;
5
+
3
6
  export function readObject(value: unknown): Record<string, unknown> {
4
7
  return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
5
8
  }
@@ -45,19 +48,63 @@ export function getOxcLocationFromOffset(
45
48
  return undefined;
46
49
  }
47
50
 
48
- let line = 1;
49
- let column = 1;
51
+ const lineStarts = getLineStarts(code);
52
+ const lineIndex = findLineStartIndex(lineStarts, start);
53
+
54
+ return {
55
+ line: lineIndex + 1,
56
+ column: start - (lineStarts[lineIndex] ?? 0) + 1,
57
+ };
58
+ }
59
+
60
+ function getLineStarts(code: string): readonly number[] {
61
+ const cached = lineStartCache.get(code);
62
+
63
+ if (cached !== undefined) {
64
+ return cached;
65
+ }
50
66
 
51
- for (let index = 0; index < start; index += 1) {
67
+ const starts = [0];
68
+
69
+ for (let index = 0; index < code.length; index += 1) {
52
70
  if (code[index] === "\n") {
53
- line += 1;
54
- column = 1;
71
+ starts.push(index + 1);
72
+ }
73
+ }
74
+
75
+ rememberLineStarts(code, starts);
76
+
77
+ return starts;
78
+ }
79
+
80
+ function rememberLineStarts(code: string, starts: readonly number[]): void {
81
+ if (lineStartCache.size >= lineStartCacheLimit) {
82
+ const first = lineStartCache.keys().next().value;
83
+
84
+ if (first !== undefined) {
85
+ lineStartCache.delete(first);
86
+ }
87
+ }
88
+
89
+ lineStartCache.set(code, starts);
90
+ }
91
+
92
+ function findLineStartIndex(lineStarts: readonly number[], offset: number): number {
93
+ let low = 0;
94
+ let high = lineStarts.length - 1;
95
+
96
+ while (low <= high) {
97
+ const middle = Math.floor((low + high) / 2);
98
+ const lineStart = lineStarts[middle] ?? 0;
99
+
100
+ if (lineStart <= offset) {
101
+ low = middle + 1;
55
102
  } else {
56
- column += 1;
103
+ high = middle - 1;
57
104
  }
58
105
  }
59
106
 
60
- return { line, column };
107
+ return Math.max(0, low - 1);
61
108
  }
62
109
 
63
110
  export function arraysEqual(left: readonly string[], right: readonly string[]): boolean {
@@ -1,10 +1,22 @@
1
1
  import type { AttributeIr, ComponentPropIr, JsxNodeIr } from "./ir.js";
2
- import { isVoidHtmlElement } from "./emit-server-shared.js";
2
+ import {
3
+ htmlAttributeName,
4
+ isDangerousHtmlAttribute,
5
+ isStaticUrlValueUnsafe,
6
+ isUrlAttribute,
7
+ isVoidHtmlElement,
8
+ } from "./emit-server-shared.js";
3
9
  import { escapeHtmlAttribute } from "@reckona/mreact-shared/html-escape";
4
10
 
5
11
  export const oxcServerStringReactNodeRenderHelperPlaceholder =
6
12
  "__mreactRenderReactNodeToString";
7
13
 
14
+ let currentOxcServerStringUrlSafeHelperName = "_urlAttrSafe";
15
+
16
+ export function setOxcServerStringUrlSafeHelperName(name: string): void {
17
+ currentOxcServerStringUrlSafeHelperName = name;
18
+ }
19
+
8
20
  export function emitOxcServerStringChildren(children: readonly JsxNodeIr[]): string {
9
21
  if (children.length === 0) {
10
22
  return '""';
@@ -52,7 +64,9 @@ function emitOxcServerStringNode(node: JsxNodeIr): string {
52
64
  return '""';
53
65
  }
54
66
 
55
- const attrs = node.attributes.map(emitOxcServerAttribute).join(" + ");
67
+ const attrs = node.attributes
68
+ .map((attr) => emitOxcServerAttribute(node.tagName, attr))
69
+ .join(" + ");
56
70
  const open =
57
71
  attrs === ""
58
72
  ? JSON.stringify(`<${node.tagName}>`)
@@ -87,18 +101,58 @@ function emitOxcServerComponentProps(
87
101
  return `{ ${entries.join(", ")} }`;
88
102
  }
89
103
 
90
- function emitOxcServerAttribute(attr: AttributeIr): string {
104
+ function emitOxcServerAttribute(tagName: string, attr: AttributeIr): string {
105
+ if (attr.kind === "spread-attr" || attr.kind === "event") {
106
+ return '""';
107
+ }
108
+
109
+ if (attr.name === "key" || attr.name === "dangerouslySetInnerHTML") {
110
+ return '""';
111
+ }
112
+
113
+ const htmlName = htmlAttributeNameForElement(tagName, attr.name);
114
+
91
115
  if (attr.kind === "static-attr") {
92
- return JSON.stringify(` ${attr.name}="${escapeHtmlAttribute(attr.value)}"`);
116
+ if (isUrlAttribute(htmlName) && isStaticUrlValueUnsafe(htmlName, attr.value)) {
117
+ return '""';
118
+ }
119
+
120
+ if (isDangerousHtmlAttribute(htmlName)) {
121
+ return '""';
122
+ }
123
+
124
+ return JSON.stringify(` ${htmlName}="${escapeHtmlAttribute(attr.value)}"`);
93
125
  }
94
126
 
95
127
  if (attr.kind === "dynamic-attr") {
96
- return `${JSON.stringify(` ${attr.name}="`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('"')}`;
128
+ if (isDangerousHtmlAttribute(htmlName)) {
129
+ return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(_value.__html) + ${JSON.stringify('"')}; return ""; })()`;
130
+ }
131
+
132
+ if (isUrlAttribute(htmlName)) {
133
+ return `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; const _checked = ${currentOxcServerStringUrlSafeHelperName}(${JSON.stringify(htmlName)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(_checked) + ${JSON.stringify('"')}; })()`;
134
+ }
135
+
136
+ return `${JSON.stringify(` ${htmlName}="`)} + _escapeHtml(${attr.code}) + ${JSON.stringify('"')}`;
97
137
  }
98
138
 
99
139
  return '""';
100
140
  }
101
141
 
142
+ function htmlAttributeNameForElement(tagName: string, name: string): string {
143
+ if (tagName === "input") {
144
+ if (name === "defaultValue") {
145
+ return "value";
146
+ }
147
+
148
+ if (name === "defaultChecked") {
149
+ return "checked";
150
+ }
151
+ }
152
+
153
+ return htmlAttributeName(name);
154
+ }
155
+
102
156
  function emitOxcCompatObjectNode(node: JsxNodeIr): string {
103
157
  if (node.kind === "text") {
104
158
  return JSON.stringify(node.value);
@@ -1,10 +1,19 @@
1
1
  import { transformSync } from "oxc-transform";
2
2
 
3
+ const stripTypeScriptCache = new Map<string, string>();
4
+ const stripTypeScriptCacheLimit = 512;
5
+
3
6
  export function stripTypeScriptWithOxc(source: string): string {
4
7
  if (!needsTypeScriptStripping(source)) {
5
8
  return source.trimEnd();
6
9
  }
7
10
 
11
+ const cached = stripTypeScriptCache.get(source);
12
+
13
+ if (cached !== undefined) {
14
+ return cached;
15
+ }
16
+
8
17
  const result = transformSync("snippet.tsx", source, {
9
18
  lang: "tsx",
10
19
  sourceType: "module",
@@ -15,11 +24,23 @@ export function stripTypeScriptWithOxc(source: string): string {
15
24
  },
16
25
  });
17
26
 
18
- if (result.errors.length > 0) {
19
- return source.trimEnd();
27
+ const stripped = result.errors.length > 0 ? source.trimEnd() : result.code.trimEnd();
28
+
29
+ rememberStrippedTypeScript(source, stripped);
30
+
31
+ return stripped;
32
+ }
33
+
34
+ function rememberStrippedTypeScript(source: string, stripped: string): void {
35
+ if (stripTypeScriptCache.size >= stripTypeScriptCacheLimit) {
36
+ const first = stripTypeScriptCache.keys().next().value;
37
+
38
+ if (first !== undefined) {
39
+ stripTypeScriptCache.delete(first);
40
+ }
20
41
  }
21
42
 
22
- return result.code.trimEnd();
43
+ stripTypeScriptCache.set(source, stripped);
23
44
  }
24
45
 
25
46
  function needsTypeScriptStripping(source: string): boolean {