diff --git a/packages/babel-utils/src/parse.js b/packages/babel-utils/src/parse.js index 55dd65c990..d75d471d9c 100644 --- a/packages/babel-utils/src/parse.js +++ b/packages/babel-utils/src/parse.js @@ -82,6 +82,33 @@ export function parseTemplateLiteral(file, str, sourceStart, sourceEnd) { return ensureParseError(file, parsed, sourceStart, sourceEnd); } +export function parseTypeArgs(file, str, sourceStart, sourceEnd) { + const parsed = parseExpression(file, `_<${str}>`, sourceStart, sourceEnd, 2); + + if (parsed.type === "TSInstantiationExpression") { + // typeArguments is Flow only (not TS), we need to use typeParameters + return parsed.typeParameters; + } + + return [ensureParseError(file, parsed, sourceStart, sourceEnd)]; +} + +export function parseTypeParams(file, str, sourceStart, sourceEnd) { + const parsed = parseExpression( + file, + `<${str}>()=>{}`, + sourceStart, + sourceEnd, + 1 + ); + + if (parsed.type === "ArrowFunctionExpression") { + return parsed.typeParameters; + } + + return [ensureParseError(file, parsed, sourceStart, sourceEnd)]; +} + function tryParse( file, isExpression, diff --git a/packages/compiler/src/babel-plugin/parser.js b/packages/compiler/src/babel-plugin/parser.js index 45b65cd316..08fbd6e70b 100644 --- a/packages/compiler/src/babel-plugin/parser.js +++ b/packages/compiler/src/babel-plugin/parser.js @@ -9,6 +9,7 @@ import { parseTemplateLiteral, parseVar, } from "@marko/babel-utils"; +import { parseTypeArgs, parseTypeParams } from "@marko/babel-utils/src/parse"; const noop = () => {}; const emptyRange = (part) => part.start === part.end; @@ -197,6 +198,22 @@ export function parseMarko(file) { onComment(part) { pushContent(withLoc(t.markoComment(parser.read(part.value)), part)); }, + onTagTypeArgs(part) { + currentTag.node.typeArguments = parseTypeArgs( + file, + parser.read(part.value), + part.start, + part.end + ); + }, + onTagTypeParams(part) { + currentTag.node.typeParameters = parseTypeParams( + file, + parser.read(part.value), + part.start, + part.end + ); + }, onPlaceholder(part) { pushContent( withLoc( diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg-and-param.marko b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg-and-param.marko new file mode 100644 index 0000000000..431ff80620 --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg-and-param.marko @@ -0,0 +1,6 @@ +export interface Input { + arg: T; + renderBody: Marko.Body<[T]>; +} + +${input.renderBody}=[input.arg]; \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg.marko b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg.marko new file mode 100644 index 0000000000..f9f1e27a99 --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-arg.marko @@ -0,0 +1,6 @@ +export interface Input { + arg1?: T; + arg2?: K; +} + +-- ${input.arg1} ${input.arg2} \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-param.marko b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-param.marko new file mode 100644 index 0000000000..6ab02d63f5 --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/components/type-param.marko @@ -0,0 +1,5 @@ +export interface Input { + renderBody: Marko.Body<[T]>; +} + +${input.renderBody}=[3 as any]; \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/cjs-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/cjs-expected.js new file mode 100644 index 0000000000..04e0bac0cc --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/cjs-expected.js @@ -0,0 +1,35 @@ +"use strict"; + +exports.__esModule = true; +exports.default = void 0; +var _index = require("marko/src/runtime/html/index.js"); +var _typeArg2 = _interopRequireDefault(require("./components/type-arg.marko")); +var _renderTag = _interopRequireDefault(require("marko/src/runtime/helpers/render-tag.js")); +var _escapeXml = require("marko/src/runtime/html/helpers/escape-xml.js"); +var _typeParam2 = _interopRequireDefault(require("./components/type-param.marko")); +var _typeArgAndParam2 = _interopRequireDefault(require("./components/type-arg-and-param.marko")); +var _renderer = _interopRequireDefault(require("marko/src/runtime/components/renderer.js")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +const _marko_componentType = "packages/translator-default/test/fixtures/typescript-generic-tag/template.marko", + _marko_template = (0, _index.t)(_marko_componentType); +var _default = _marko_template; +exports.default = _default; +const _marko_component = {}; +_marko_template._ = (0, _renderer.default)(function (input, out, _componentDef, _component, state, $global) { + (0, _renderTag.default)(_typeArg2.default, {}, out, _componentDef, "0"); + (0, _renderTag.default)(_typeParam2.default, { + "renderBody": (out, x) => { + out.w((0, _escapeXml.x)(x)); + } + }, out, _componentDef, "1"); + (0, _renderTag.default)(_typeArgAndParam2.default, { + "arg": "hello", + "renderBody": (out, x) => { + out.w((0, _escapeXml.x)(x)); + } + }, out, _componentDef, "2"); +}, { + t: _marko_componentType, + i: true, + d: true +}, _marko_component); \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/generated-expected.marko b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/generated-expected.marko new file mode 100644 index 0000000000..2cfd56ff9d --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/generated-expected.marko @@ -0,0 +1,7 @@ + + + ${x} + + + ${x} + \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/html-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/html-expected.js new file mode 100644 index 0000000000..40c91cfbe8 --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/html-expected.js @@ -0,0 +1,29 @@ +import { t as _t } from "marko/src/runtime/html/index.js"; +const _marko_componentType = "packages/translator-default/test/fixtures/typescript-generic-tag/template.marko", + _marko_template = _t(_marko_componentType); +export default _marko_template; +import _typeArg from "./components/type-arg.marko"; +import _marko_tag from "marko/src/runtime/helpers/render-tag.js"; +import { x as _marko_escapeXml } from "marko/src/runtime/html/helpers/escape-xml.js"; +import _typeParam from "./components/type-param.marko"; +import _typeArgAndParam from "./components/type-arg-and-param.marko"; +import _marko_renderer from "marko/src/runtime/components/renderer.js"; +const _marko_component = {}; +_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) { + _marko_tag(_typeArg, {}, out, _componentDef, "0"); + _marko_tag(_typeParam, { + "renderBody": (out, x) => { + out.w(_marko_escapeXml(x)); + } + }, out, _componentDef, "1"); + _marko_tag(_typeArgAndParam, { + "arg": "hello", + "renderBody": (out, x) => { + out.w(_marko_escapeXml(x)); + } + }, out, _componentDef, "2"); +}, { + t: _marko_componentType, + i: true, + d: true +}, _marko_component); \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/htmlProduction-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/htmlProduction-expected.js new file mode 100644 index 0000000000..960741c46c --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/htmlProduction-expected.js @@ -0,0 +1,28 @@ +import { t as _t } from "marko/dist/runtime/html/index.js"; +const _marko_componentType = "H1mF9+h2", + _marko_template = _t(_marko_componentType); +export default _marko_template; +import _typeArg from "./components/type-arg.marko"; +import _marko_tag from "marko/dist/runtime/helpers/render-tag.js"; +import { x as _marko_escapeXml } from "marko/dist/runtime/html/helpers/escape-xml.js"; +import _typeParam from "./components/type-param.marko"; +import _typeArgAndParam from "./components/type-arg-and-param.marko"; +import _marko_renderer from "marko/dist/runtime/components/renderer.js"; +const _marko_component = {}; +_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) { + _marko_tag(_typeArg, {}, out, _componentDef, "0"); + _marko_tag(_typeParam, { + "renderBody": (out, x) => { + out.w(_marko_escapeXml(x)); + } + }, out, _componentDef, "1"); + _marko_tag(_typeArgAndParam, { + "arg": "hello", + "renderBody": (out, x) => { + out.w(_marko_escapeXml(x)); + } + }, out, _componentDef, "2"); +}, { + t: _marko_componentType, + i: true +}, _marko_component); \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/hydrate-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/hydrate-expected.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdom-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdom-expected.js new file mode 100644 index 0000000000..20acc5b36f --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdom-expected.js @@ -0,0 +1,32 @@ +import { t as _t } from "marko/src/runtime/vdom/index.js"; +const _marko_componentType = "packages/translator-default/test/fixtures/typescript-generic-tag/template.marko", + _marko_template = _t(_marko_componentType); +export default _marko_template; +import _typeArg from "./components/type-arg.marko"; +import _marko_tag from "marko/src/runtime/helpers/render-tag.js"; +import _typeParam from "./components/type-param.marko"; +import _typeArgAndParam from "./components/type-arg-and-param.marko"; +import _marko_renderer from "marko/src/runtime/components/renderer.js"; +import { r as _marko_registerComponent } from "marko/src/runtime/components/registry.js"; +_marko_registerComponent(_marko_componentType, () => _marko_template); +const _marko_component = {}; +_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) { + _marko_tag(_typeArg, {}, out, _componentDef, "0"); + _marko_tag(_typeParam, { + "renderBody": (out, x) => { + out.t(x, _component); + } + }, out, _componentDef, "1"); + _marko_tag(_typeArgAndParam, { + "arg": "hello", + "renderBody": (out, x) => { + out.t(x, _component); + } + }, out, _componentDef, "2"); +}, { + t: _marko_componentType, + i: true, + d: true +}, _marko_component); +import _marko_defineComponent from "marko/src/runtime/components/defineComponent.js"; +_marko_template.Component = _marko_defineComponent(_marko_component, _marko_template._); \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdomProduction-expected.js b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdomProduction-expected.js new file mode 100644 index 0000000000..63d563dd6b --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/snapshots/vdomProduction-expected.js @@ -0,0 +1,31 @@ +import { t as _t } from "marko/dist/runtime/vdom/index.js"; +const _marko_componentType = "H1mF9+h2", + _marko_template = _t(_marko_componentType); +export default _marko_template; +import _typeArg from "./components/type-arg.marko"; +import _marko_tag from "marko/dist/runtime/helpers/render-tag.js"; +import _typeParam from "./components/type-param.marko"; +import _typeArgAndParam from "./components/type-arg-and-param.marko"; +import _marko_renderer from "marko/dist/runtime/components/renderer.js"; +import { r as _marko_registerComponent } from "marko/dist/runtime/components/registry.js"; +_marko_registerComponent(_marko_componentType, () => _marko_template); +const _marko_component = {}; +_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) { + _marko_tag(_typeArg, {}, out, _componentDef, "0"); + _marko_tag(_typeParam, { + "renderBody": (out, x) => { + out.t(x, _component); + } + }, out, _componentDef, "1"); + _marko_tag(_typeArgAndParam, { + "arg": "hello", + "renderBody": (out, x) => { + out.t(x, _component); + } + }, out, _componentDef, "2"); +}, { + t: _marko_componentType, + i: true +}, _marko_component); +import _marko_defineComponent from "marko/dist/runtime/components/defineComponent.js"; +_marko_template.Component = _marko_defineComponent(_marko_component, _marko_template._); \ No newline at end of file diff --git a/packages/translator-default/test/fixtures/typescript-generic-tag/template.marko b/packages/translator-default/test/fixtures/typescript-generic-tag/template.marko new file mode 100644 index 0000000000..e805d45421 --- /dev/null +++ b/packages/translator-default/test/fixtures/typescript-generic-tag/template.marko @@ -0,0 +1,3 @@ + /> +|x: T & U|>${x} +|x: T| arg="hello">${x} \ No newline at end of file