Skip to content
Draft
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dbf58c5
Adding empty project for the TypeSpec library.
glecaros Oct 13, 2025
c440fb7
Ported name over to this branch
jpalvarezl Oct 14, 2025
d1e29f3
Added import statements
jpalvarezl Oct 14, 2025
c7b15e5
Added a couple of clarifying remarks
jpalvarezl Oct 14, 2025
fe648d9
Added source-file.tsx
jpalvarezl Oct 14, 2025
0ec982e
Added all the entities in #1
jpalvarezl Oct 14, 2025
f016b14
Added missing imports
jpalvarezl Oct 14, 2025
f4b1e0a
Added model-property too
jpalvarezl Oct 15, 2025
54b2498
Added regex validation for some element names in policy
jpalvarezl Oct 15, 2025
df9cbc4
Adding scopes, symbols and context
jpalvarezl Oct 16, 2025
a9ea352
PR feedback and disabling modelProperty
jpalvarezl Oct 17, 2025
5948676
added namespace-scope for components and moved tests
jpalvarezl Oct 17, 2025
260703d
focusing on namespace.test.tsx at least now the scope is not undefined
jpalvarezl Oct 17, 2025
f5221a1
Added missing JSX
jpalvarezl Oct 17, 2025
e44cf8e
Zoning in the problem
jpalvarezl Oct 17, 2025
321666b
Going down the source-file rabbit hole
jpalvarezl Oct 17, 2025
5e9fe05
Added TestNamespace util
jpalvarezl Oct 17, 2025
b657164
WIP
jpalvarezl Oct 17, 2025
daf16a2
WIP
jpalvarezl Oct 17, 2025
c0639b8
Fixed compilation
jpalvarezl Oct 17, 2025
4f80830
Simplified source just to see if I am able to render something
jpalvarezl Oct 17, 2025
e184200
Add directory.
glecaros Oct 27, 2025
bf121bf
asdf
glecaros Oct 27, 2025
74c06fd
wip
glecaros Oct 27, 2025
a972a51
Merge branch 'feature/typespec' into jpalvarezl/base_context
glecaros Oct 28, 2025
e3b6d51
namespaces!
glecaros Oct 28, 2025
15839e4
PR feedback and cleanup
jpalvarezl Oct 29, 2025
55a5e05
Removed more unnecessary code at this point
jpalvarezl Oct 30, 2025
db7d4ca
WIP: getting namespace as props not working yet
jpalvarezl Oct 30, 2025
8421dee
WIP: still failing but now both failing tests create the namespacesym…
jpalvarezl Oct 30, 2025
b41eada
fixed one more test
jpalvarezl Nov 3, 2025
a9929d4
Consolidated namespaces under single component type
jpalvarezl Nov 3, 2025
6390c62
Removed setting of removed flagged
jpalvarezl Nov 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/typespec/src/components/Reference.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as core from "@alloy-js/core";
import { ref } from "../symbols/reference.js";

export interface ReferenceProps {
refkey: core.Refkey;
}

// used to resolve refkey references within source files
export function Reference({ refkey }: ReferenceProps) {
const reference = ref(refkey);
const symbolRef = core.computed(() => reference()[1]);

core.emitSymbol(symbolRef);
return <>{reference()[0]}</>;
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/alias.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface AliasProps {};

export function Alias(props: AliasProps) {
return <></>;
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/decorator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface DecoratorProps {};

export function Decorator(props: DecoratorProps) {
return <></>;
}
19 changes: 19 additions & 0 deletions packages/typespec/src/components/directory/directory.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { expect, it } from "vitest";
import { Directory } from "./directory.jsx";
import { Output, SourceFile } from "@alloy-js/core";

it("defines multiple directories with unique source files", () => {
expect(
<Output>
<Directory path="dir1">
<SourceFile path="file.tsp" filetype="tsp">Content of File1</SourceFile>
</Directory>
<Directory path="dir2">
<SourceFile path="file.tsp" filetype="tsp">Content of File2</SourceFile>
</Directory>
</Output>,
).toRenderTo({
"dir1/file.tsp": `Content of File1`,
"dir2/file.tsp": `Content of File2`,
});
});
18 changes: 18 additions & 0 deletions packages/typespec/src/components/directory/directory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Children, Scope, SourceDirectory } from "@alloy-js/core";
import { createDirectoryScope } from "../../symbols/factories.js";

export interface DirectoryProps {
path: string;
children?: Children;
};

export function Directory(props: DirectoryProps) {
const scope = createDirectoryScope(props.path);
return (
<SourceDirectory path={props.path}>
<Scope value={scope}>
{props.children}
</Scope>
</SourceDirectory>
);
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/enum.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface EnumProps {};

export function Enum(props: EnumProps) {
return <></>;
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/import.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ImportProps {};

export function Import(props: ImportProps) {
return <></>;
}
14 changes: 14 additions & 0 deletions packages/typespec/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export * from "./alias.jsx";
export * from "./decorator.jsx";
export * from "./enum.jsx";
export * from "./import.jsx";
export * from "./interface.jsx";
export * from "./model-property.jsx";
export * from "./model.jsx";
export * from "./namespace.jsx";
export * from "./operation.jsx"
export * from "./scalar.jsx";
export * from "./directory/directory.jsx"
export * from "./source-file/source-file.jsx";
export * from "./union.jsx";
export * from "./value.jsx";
5 changes: 5 additions & 0 deletions packages/typespec/src/components/interface.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface InterfaceProps {};

export function Interface(props: InterfaceProps) {
return <></>;
}
18 changes: 18 additions & 0 deletions packages/typespec/src/components/model-property.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Children, createNamedContext, Declaration, Name } from "@alloy-js/core";
import { createPropertySymbol } from "../symbols/factories.js";

export interface ModelPropertyProps {
name: string;
doc?: Children;
};

export function ModelProperty(props: ModelPropertyProps) {
// const symbol = createPropertySymbol(props.name);

// return (
// <Declaration symbol={symbol}>
// <Name />
// </Declaration>
// );
return <></>;
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/model.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ModelProps {};

export function Model(props: ModelProps) {
return <></>;
}
63 changes: 63 additions & 0 deletions packages/typespec/src/components/namespace/block.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { expect, it } from "vitest";
import { Output } from "@alloy-js/core";
import { Directory } from "#components/directory/directory.jsx";
import { SourceFile } from "#components/source-file/source-file.jsx";
import { Namespace } from "./block.jsx";
import { d } from "@alloy-js/core/testing";

it("renders a namespace with contents", () => {
expect(
<Output>
<SourceFile path="main.tsp">
<Namespace name="My.Namespace">
Contents!
</Namespace>
</SourceFile>
</Output>,
).toRenderTo({
"main.tsp": d`
namespace My.Namespace {
Contents!
}`,
});
});

it("renders nested block namespaces", () => {
expect(
<Output>
<SourceFile path="main.tsp">
<Namespace name="My.Namespace">
<Namespace name="Inner.Namespace">
Inner Contents!
</Namespace>
</Namespace>
</SourceFile>
</Output>,
).toRenderTo({
"main.tsp": d`
namespace My.Namespace {
namespace Inner.Namespace {
Inner Contents!
}
}`,
});
});

it("renders namespaces when a file level namespace is present", () => {
expect(
<Output>
<SourceFile path="main.tsp" namespace="File.Level">
<Namespace name="My.Namespace">
Contents!
</Namespace>
</SourceFile>
</Output>,
).toRenderTo({
"main.tsp": d`
namespace File.Level;

namespace My.Namespace {
Contents!
}`,
});
});
35 changes: 35 additions & 0 deletions packages/typespec/src/components/namespace/block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Block, Children, Namekey, Refkey, Scope, useScope } from "@alloy-js/core";
import { NamespaceScope, useNamespace } from "../../scopes/namespace.js";
import { createNamespaceSymbol } from "../../symbols/factories.js";
import { Declaration } from "../../../../core/src/index.browser.js";

export interface NamespaceProps {
name: string | Namekey | (string | Namekey)[];
refkey?: Refkey | Refkey[];
children?: Children;
}

export function Namespace(props: NamespaceProps) {
const parent = useNamespace();

if (parent === undefined) {
throw new Error("Block namespace must be declared within another namespace.");
}

const symbol = createNamespaceSymbol(props.name, {
refkeys: props.refkey,
});

const scope = new NamespaceScope(symbol, parent);
const name = symbol.getScopedName(parent.ownerSymbol);

return (
<Scope value={scope}>
<Declaration symbol={symbol}>
namespace {name} <Block>
{props.children}
</Block>
</Declaration>
</Scope>
);
}
52 changes: 52 additions & 0 deletions packages/typespec/src/components/namespace/file-level.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Children, Declaration, Name, Namekey, Refkey, Scope, Show, useBinder } from "@alloy-js/core";
import { useSourceFileScope } from "../../scopes/source-file.js";
import { getGlobalNamespace } from "../../contexts/global-namespace.js";
import { NamespaceSymbol } from "../../symbols/namespace.js";
import { createNamespaceSymbol } from "../../symbols/factories.js";
import { NamespaceScope } from "../../scopes/namespace.js";

export interface FileLevelNamespaceProps {
name?: string | Namekey | (string | Namekey)[];
refkey?: Refkey | Refkey[];
children?: Children;
isGlobal?: boolean;
}

export function FileLevelNamespace(props: FileLevelNamespaceProps) {
if (props.name === undefined && !props.isGlobal) {
throw new Error("File level namespace requires a name or global flag");
}
if (props.name !== undefined && props.isGlobal) {
throw new Error("File level namespace cannot have both a name and global flag");
}

const parent = useSourceFileScope();
if (parent === undefined) {
throw new Error("File level namespace must be used within a source file scope");
}

let symbol: NamespaceSymbol;
if (props.name === undefined) {
symbol = getGlobalNamespace(useBinder());
} else {
symbol = createNamespaceSymbol(props.name, {
refkeys: props.refkey,
});
}

const namespaceScope = new NamespaceScope(symbol, parent);

return (
<Scope value={namespaceScope} >
<Declaration symbol={symbol}>
<Show when={!props.isGlobal}>
namespace {symbol.getFullyQualifiedName()};
<hbr />
<hbr />
</Show>
{props.children}
</Declaration>
</Scope>
)

}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/operation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface OperationProps {};

export function Operation(props: OperationProps) {
return <></>;
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/scalar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ScalarProps {};

export function Scalar(props: ScalarProps) {
return <></>;
}
33 changes: 33 additions & 0 deletions packages/typespec/src/components/source-file/source-file.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect, it } from "vitest";
import { Output } from "@alloy-js/core";
import { SourceFile } from "./source-file.jsx";
import { Directory } from "#components/directory/directory.jsx";

it("defines multiple directories with unique source files", () => {
expect(
<Output>
<Directory path="dir1">
<SourceFile path="file.tsp">Content of File1</SourceFile>
</Directory>
<Directory path="dir2">
<SourceFile path="file.tsp">Content of File2</SourceFile>
</Directory>
</Output>,
).toRenderTo({
"dir1/file.tsp": `Content of File1`,
"dir2/file.tsp": `Content of File2`,
});
});

it("declares a file level namespace when one is provided", () => {
expect(
<Output>
<SourceFile namespace="My.Namespace" path="main.tsp">
</SourceFile>
</Output>
).toRenderTo({
"main.tsp": `
namespace My.Namespace;
`,
});
});
52 changes: 52 additions & 0 deletions packages/typespec/src/components/source-file/source-file.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Children } from "@alloy-js/core/jsx-runtime";
import { SourceFileScope } from "../../scopes/source-file.js";
import { SourceFile as CoreSourceFile, Scope } from "@alloy-js/core";
import {
useTypeSpecFormatOptions
} from "../../contexts/format-options.js";
import { Reference } from "../Reference.jsx";
import { useDirectoryScope } from "../../scopes/contexts.js";
import { FileLevelNamespace } from "#components/namespace/file-level.jsx";

export interface SourceFileProps {
path: string;

/** If present, it defines a file-level namespace (if not present, it uses the global namespace) */
namespace?: string;

children?: Children;

/**
* A list of using directives to explicitly include. Note that providing
* explicit usings is not necessary when referencing symbols via refkeys.
*/
using?: string[];

/**
* A list of import directives to explicitly include. Note that providing
* explicit imports is not necessary when referencing symbols via refkeys.
*/
import?: string[];
};

export function SourceFile(props: SourceFileProps) {
const parent = useDirectoryScope();
const sourceFileScope = new SourceFileScope(props.path, parent);

const options = useTypeSpecFormatOptions();

return (
<CoreSourceFile
path={props.path}
filetype=".tsp"
reference={Reference}
{...options}
>
<Scope value={sourceFileScope}>
<FileLevelNamespace name={props.namespace} isGlobal={props.namespace === undefined}>
{props.children}
</FileLevelNamespace>
</Scope>
</CoreSourceFile>
);
}
5 changes: 5 additions & 0 deletions packages/typespec/src/components/union.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface UnionProps {};

export function Union(props: UnionProps) {
return <></>;
}
Loading