Skip to content

Commit

Permalink
Add linter selection to playground (#2386)
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeguerin authored Sep 11, 2023
1 parent 4b0eb8e commit e098c94
Show file tree
Hide file tree
Showing 18 changed files with 273 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tryit-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
`Changes in this PR will be published to the following url to try(check status of TypeSpec Pull Request Try It pipeline for publish status):`,
`Playground: https://cadlplayground.z22.web.core.windows.net/prs/${prNumber}/`,
"",
`Website: https://cadlwebsite.z1.web.core.windows.net/prs/${prNumber}/`,
`Website: https://tspwebsitepr.z5.web.core.windows.net/prs/${prNumber}/`,
].join("\n")
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@typespec/compiler",
"comment": "Expose `CompilerOptions` TypeScript type",
"type": "none"
}
],
"packageName": "@typespec/compiler"
}
2 changes: 1 addition & 1 deletion eng/pipelines/pr-tryit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
inlineScript: |
az storage blob upload-batch \
--destination \$web \
--account-name "cadlwebsite" \
--account-name "tspwebsitepr" \
--destination-path $(TYPESPEC_WEBSITE_BASE_PATH) \
--source "./packages/website/build/" \
--overwrite
Expand Down
2 changes: 1 addition & 1 deletion eng/scripts/create-tryit-comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async function main() {
`<!-- ${TRY_ID_COMMENT_IDENTIFIER} -->`,
`You can try these changes at https://cadlplayground.z22.web.core.windows.net${folderName}/prs/${prNumber}/`,
"",
`Check the website changes at https://cadlwebsite.z1.web.core.windows.net${folderName}/prs/${prNumber}/`,
`Check the website changes at https://tspwebsitepr.z5.web.core.windows.net${folderName}/prs/${prNumber}/`,
].join("\n");
await writeComment(repo, prNumber, comment, ghAuth);
}
Expand Down
1 change: 1 addition & 0 deletions packages/compiler/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
} from "./library.js";
export * from "./module-resolver.js";
export * from "./node-host.js";
export * from "./options.js";
export * from "./parser.js";
export * from "./path-utils.js";
export * from "./program.js";
Expand Down
12 changes: 10 additions & 2 deletions packages/playground-website/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ const config = definePlaygroundViteConfig({
filename: "samples/unions.tsp",
preferredEmitter: "@typespec/openapi3",
},
"HTTP service": { filename: "samples/http.tsp", preferredEmitter: "@typespec/openapi3" },
"REST framework": { filename: "samples/rest.tsp", preferredEmitter: "@typespec/openapi3" },
"HTTP service": {
filename: "samples/http.tsp",
preferredEmitter: "@typespec/openapi3",
compilerOptions: { linterRuleSet: { extends: ["@typespec/http/all"] } },
},
"REST framework": {
filename: "samples/rest.tsp",
preferredEmitter: "@typespec/openapi3",
compilerOptions: { linterRuleSet: { extends: ["@typespec/http/all"] } },
},
"Protobuf Kiosk": {
filename: "samples/kiosk.tsp",
preferredEmitter: "@typespec/protobuf",
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export { registerMonacoDefaultWorkers } from "./monaco-worker.js";
export { registerMonacoLanguage } from "./services.js";
export { createUrlStateStorage } from "./state-storage.js";
export { PlaygroundSample } from "./types.js";
export { filterEmitters } from "./utils.js";
export { resolveLibraries as filterEmitters } from "./utils.js";
24 changes: 13 additions & 11 deletions packages/playground/src/react/editor-command-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,23 @@ import {
Tooltip,
} from "@fluentui/react-components";
import { Bug16Regular, Save16Regular, Settings24Regular } from "@fluentui/react-icons";
import { CompilerOptions } from "@typespec/compiler";
import { FunctionComponent } from "react";
import { PlaygroundSample } from "../types.js";
import { EmitterDropdown } from "./emitter-dropdown.js";
import { OutputSettings } from "./output-settings.js";
import { SamplesDropdown } from "./samples-dropdown.js";
import { EmitterOptions } from "./types.js";
import { CompilerSettings } from "./settings/compiler-settings.js";
import { PlaygroundTspLibrary } from "./types.js";

export interface EditorCommandBarProps {
documentationUrl?: string;
saveCode: () => Promise<void> | void;
newIssue?: () => Promise<void> | void;
emitters: string[];
libraries: PlaygroundTspLibrary[];
selectedEmitter: string;
onSelectedEmitterChange: (emitter: string) => void;
emitterOptions: EmitterOptions;
onEmitterOptionsChange: (options: EmitterOptions) => void;
compilerOptions: CompilerOptions;
onCompilerOptionsChange: (options: CompilerOptions) => void;

samples?: Record<string, PlaygroundSample>;
selectedSampleName: string;
Expand All @@ -35,11 +36,11 @@ export const EditorCommandBar: FunctionComponent<EditorCommandBarProps> = ({
documentationUrl,
saveCode,
newIssue,
emitters,
libraries,
selectedEmitter,
onSelectedEmitterChange,
emitterOptions,
onEmitterOptionsChange,
compilerOptions: emitterOptions,
onCompilerOptionsChange,
samples,
selectedSampleName,
onSelectedSampleNameChange,
Expand Down Expand Up @@ -73,7 +74,7 @@ export const EditorCommandBar: FunctionComponent<EditorCommandBarProps> = ({
/>
)}
<EmitterDropdown
emitters={emitters}
emitters={libraries.filter((x) => x.isEmitter).map((x) => x.name)}
onSelectedEmitterChange={onSelectedEmitterChange}
selectedEmitter={selectedEmitter}
/>
Expand All @@ -83,10 +84,11 @@ export const EditorCommandBar: FunctionComponent<EditorCommandBarProps> = ({
</DialogTrigger>
<DialogSurface>
<DialogBody>
<OutputSettings
<CompilerSettings
libraries={libraries}
selectedEmitter={selectedEmitter}
options={emitterOptions}
optionsChanged={onEmitterOptionsChange}
onOptionsChanged={onCompilerOptionsChange}
/>
</DialogBody>
</DialogSurface>
Expand Down
15 changes: 15 additions & 0 deletions packages/playground/src/react/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,18 @@ export function useControllableValue<TValue>(

return [currentValue, setValueOrCallOnChange] as any;
}

export function useAsyncMemo<T>(
callback: () => Promise<T>,
defaultValue: T,
deps?: React.DependencyList
): T {
const [value, setValue] = useState<T>(defaultValue);
useEffect(() => {
callback()
.then(setValue)
// eslint-disable-next-line no-console
.catch(() => console.error("Failed to load async memo"));
}, deps);
return value;
}
60 changes: 36 additions & 24 deletions packages/playground/src/react/playground.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CompilerOptions } from "@typespec/compiler";
import debounce from "debounce";
import { KeyCode, KeyMod, MarkerSeverity, Uri, editor } from "monaco-editor";
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from "react";
Expand All @@ -7,12 +8,13 @@ import { BrowserHost } from "../browser-host.js";
import { importTypeSpecCompiler } from "../core.js";
import { getMarkerLocation } from "../services.js";
import { PlaygroundSample } from "../types.js";
import { resolveLibraries } from "../utils.js";
import { EditorCommandBar } from "./editor-command-bar.js";
import { useMonacoModel } from "./editor.js";
import { Footer } from "./footer.js";
import { useControllableValue } from "./hooks.js";
import { useAsyncMemo, useControllableValue } from "./hooks.js";
import { OutputView } from "./output-view.js";
import { CompilationState, EmitterOptions, FileOutputViewer } from "./types.js";
import { CompilationState, FileOutputViewer } from "./types.js";
import { TypeSpecEditor } from "./typespec-editor.js";

export interface PlaygroundProps {
Expand All @@ -21,8 +23,8 @@ export interface PlaygroundProps {
/** Default emitter if leaving this unmanaged. */
defaultContent?: string;

/** List of available emitters */
emitters: string[];
/** List of available libraries */
libraries: string[];

/** Emitter to use */
emitter?: string;
Expand All @@ -32,11 +34,11 @@ export interface PlaygroundProps {
onEmitterChange?: (emitter: string) => void;

/** Emitter options */
emitterOptions?: EmitterOptions;
compilerOptions?: CompilerOptions;
/** Default emitter options if leaving this unmanaged. */
defaultEmitterOptions?: EmitterOptions;
defaultCompilerOptions?: CompilerOptions;
/** Callback when emitter options change */
onEmitterOptionsChange?: (emitter: EmitterOptions) => void;
onCompilerOptionsChange?: (emitter: CompilerOptions) => void;

/** Samples available */
samples?: Record<string, PlaygroundSample>;
Expand Down Expand Up @@ -65,7 +67,7 @@ export interface PlaygroundSaveData {
emitter: string;

/** Emitter options. */
options?: EmitterOptions;
options?: CompilerOptions;

/** If a sample is selected and the content hasn't changed since. */
sampleName?: string;
Expand All @@ -85,10 +87,10 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
props.defaultEmitter,
props.onEmitterChange
);
const [emitterOptions, onEmitterOptionsChange] = useControllableValue(
props.emitterOptions,
props.defaultEmitterOptions ?? {},
props.onEmitterOptionsChange
const [compilerOptions, onCompilerOptionsChange] = useControllableValue(
props.compilerOptions,
props.defaultCompilerOptions ?? {},
props.onCompilerOptionsChange
);
const [selectedSampleName, onSelectedSampleNameChange] = useControllableValue(
props.sampleName,
Expand All @@ -107,7 +109,7 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
setContent(content);
const typespecCompiler = await importTypeSpecCompiler();

const state = await compile(host, content, selectedEmitter, emitterOptions);
const state = await compile(host, content, selectedEmitter, compilerOptions);
setCompilationState(state);
if ("program" in state) {
const markers: editor.IMarkerData[] = state.program.diagnostics.map((diag) => ({
Expand All @@ -121,7 +123,7 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
} else {
editor.setModelMarkers(typespecModel, "owner", []);
}
}, [host, selectedEmitter, emitterOptions, typespecModel, setContent]);
}, [host, selectedEmitter, compilerOptions, typespecModel, setContent]);

const updateTypeSpec = useCallback(
(value: string) => {
Expand All @@ -143,6 +145,9 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
if (config.preferredEmitter) {
onSelectedEmitterChange(config.preferredEmitter);
}
if (config.compilerOptions) {
onCompilerOptionsChange(config.compilerOptions);
}
}
}
}, [updateTypeSpec, selectedSampleName]);
Expand All @@ -165,15 +170,15 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
onSave({
content: typespecModel.getValue(),
emitter: selectedEmitter,
options: emitterOptions,
options: compilerOptions,
sampleName: isSampleUntouched ? selectedSampleName : undefined,
});
}
}, [
typespecModel,
onSave,
selectedEmitter,
emitterOptions,
compilerOptions,
selectedSampleName,
isSampleUntouched,
]);
Expand All @@ -193,6 +198,12 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
[saveCode]
);

const libraries = useAsyncMemo(
async () => resolveLibraries(props.libraries),
[],
[props.libraries]
);

return (
<div
css={{
Expand All @@ -208,11 +219,11 @@ export const Playground: FunctionComponent<PlaygroundProps> = (props) => {
>
<div css={{ gridArea: "typespeceditor", width: "100%", height: "100%", overflow: "hidden" }}>
<EditorCommandBar
emitters={props.emitters}
libraries={libraries}
selectedEmitter={selectedEmitter}
onSelectedEmitterChange={onSelectedEmitterChange}
emitterOptions={emitterOptions}
onEmitterOptionsChange={onEmitterOptionsChange}
compilerOptions={compilerOptions}
onCompilerOptionsChange={onCompilerOptionsChange}
samples={props.samples}
selectedSampleName={selectedSampleName}
onSelectedSampleNameChange={onSelectedSampleNameChange}
Expand Down Expand Up @@ -247,22 +258,23 @@ async function compile(
host: BrowserHost,
content: string,
selectedEmitter: string,
emittersOptions: Record<string, Record<string, unknown>>
options: CompilerOptions
): Promise<CompilationState> {
await host.writeFile("main.tsp", content);
await emptyOutputDir(host);
try {
const typespecCompiler = await importTypeSpecCompiler();
const program = await typespecCompiler.compile(host, "main.tsp", {
outputDir: "tsp-output",
emit: [selectedEmitter],
...options,
options: {
...emittersOptions,
...options.options,
[selectedEmitter]: {
...emittersOptions[selectedEmitter],
...options.options?.[selectedEmitter],
"emitter-output-dir": "tsp-output",
},
},
outputDir: "tsp-output",
emit: [selectedEmitter],
});
const outputFiles = await findOutputFiles(host);
return { program, outputFiles };
Expand Down
Loading

0 comments on commit e098c94

Please sign in to comment.