Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[http-server-javascript] Merge JavaScript Server Generator to Main #3231

Merged
merged 39 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
67822c2
Move javascript HTTP server generator to typespec repo
willmtemple Apr 24, 2024
6feb456
Added more package metadata.
willmtemple Apr 24, 2024
efa5b59
Standardize configs, lint package, remove dead code
willmtemple Apr 24, 2024
c761450
Add generated documentation
willmtemple Apr 24, 2024
97ee3cd
Implemented helpers, several changes for strict correctness, and fixe…
willmtemple May 1, 2024
cd1a448
Implemented shared-route differentiation by content-type
willmtemple May 13, 2024
ba4cfb2
Removed some old TODO comments
willmtemple May 13, 2024
1f6d1ba
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple May 13, 2024
fb2d462
Merge value rework PR
willmtemple May 13, 2024
dc6de85
Added type differentiation logic
willmtemple May 18, 2024
f5231a1
Add copyright headers
willmtemple May 31, 2024
21b2f1f
Implement union serde
willmtemple Jun 3, 2024
8b97d74
Several improvements to differentiation, allowing for literals and ra…
willmtemple Jun 24, 2024
3c690d8
Move LiteralType extension to http-server-javascript instead of core
willmtemple Jun 25, 2024
0dc804d
README
willmtemple Jul 2, 2024
eb2a617
eqeq
willmtemple Jul 2, 2024
4f2cf29
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 2, 2024
81ffac0
Fix build error from merge
willmtemple Jul 2, 2024
871ae73
Fixed several build errors
willmtemple Jul 5, 2024
80bde56
Merge remote-tracking branch 'origin/http-server-javascript' into htt…
willmtemple Jul 5, 2024
caeccde
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 5, 2024
47d79d2
Address CodeQL, disable doc generation
willmtemple Jul 8, 2024
953f9b3
Addressed PR feedback.
willmtemple Jul 9, 2024
8f04469
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 9, 2024
7bf5dd0
Fixed string escaping
willmtemple Jul 9, 2024
a28c5f1
Removed vestigial 'features' functionality
willmtemple Jul 9, 2024
9302d27
Strengthen warning
willmtemple Jul 9, 2024
51873e3
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 9, 2024
8c19466
Remove all TODOs, converted to issues.
willmtemple Jul 9, 2024
347ba0b
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 9, 2024
d2e5353
update pnpm-lock with new pnpm version
willmtemple Jul 9, 2024
4c68409
Address remaining feedback
willmtemple Jul 10, 2024
eeabef4
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 10, 2024
ec3512f
Fixed depedencies.
willmtemple Jul 10, 2024
d08525a
Invert helper src and generated output directories.
willmtemple Jul 10, 2024
d7223a9
Fix regression in content-type logic
willmtemple Jul 10, 2024
e30126f
Merge remote-tracking branch 'upstream/main' into http-server-javascript
willmtemple Jul 10, 2024
9f5a389
Ignore formatting in generated helper lines.
willmtemple Jul 10, 2024
a93750f
EOL -> \n
willmtemple Jul 10, 2024
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
36 changes: 36 additions & 0 deletions docs/libraries/http-server-javascript/reference/emitter.md
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: "Emitter usage"
toc_min_heading_level: 2
toc_max_heading_level: 3
---

# Emitter

## Usage

1. Via the command line

```bash
tsp compile . --emit=@typespec/http-server-javascript
```

2. Via the config

```yaml
emit:
- "@typespec/http-server-javascript"
```

## Emitter options

### `features`

**Type:** `object`

### `omit-unreachable-types`

**Type:** `boolean`

### `no-format`

**Type:** `boolean`
36 changes: 36 additions & 0 deletions docs/libraries/http-server-javascript/reference/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Overview
sidebar_position: 0
toc_min_heading_level: 2
toc_max_heading_level: 3
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Overview

TypeSpec HTTP server code generator for JavaScript

## Install

<Tabs>
<TabItem value="spec" label="In a spec" default>

```bash
npm install @typespec/http-server-javascript
```

</TabItem>
<TabItem value="library" label="In a library" default>

```bash
npm install --save-peer @typespec/http-server-javascript
```

</TabItem>
</Tabs>

## Emitter usage

[See documentation](./emitter.md)
1 change: 1 addition & 0 deletions packages/http-server-javascript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/helpers
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved
21 changes: 21 additions & 0 deletions packages/http-server-javascript/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
40 changes: 40 additions & 0 deletions packages/http-server-javascript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# @typespec/http-server-javascript

TypeSpec HTTP server code generator for JavaScript

## Install

```bash
npm install @typespec/http-server-javascript
```

## Emitter

### Usage

1. Via the command line

```bash
tsp compile . --emit=@typespec/http-server-javascript
```

2. Via the config

```yaml
emit:
- "@typespec/http-server-javascript"
```

### Emitter options

#### `features`

**Type:** `object`

#### `omit-unreachable-types`

**Type:** `boolean`

#### `no-format`

**Type:** `boolean`
167 changes: 167 additions & 0 deletions packages/http-server-javascript/build-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/* eslint-disable */
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved

import fs from "node:fs/promises";
import { EOL } from "node:os";
import path from "node:path";

const HELPER_DECLARATION_PATH = path.resolve([".", "src", "helpers"].join(path.sep));
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved
const HELPER_SRC_PATH = path.resolve([".", "helpers"].join(path.sep));
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved

console.log("Building JS server generator helpers.");

async function* visitAllFiles(base: string): AsyncIterable<string> {
const contents = await fs.readdir(base, { withFileTypes: true });

for (const entry of contents) {
if (entry.isDirectory()) {
yield* visitAllFiles(path.join(base, entry.name));
} else if (entry.isFile()) {
yield path.join(base, entry.name);
}
}
}

async function main() {
const allFiles = [];
const indices = new Map<string, string[]>();

const ctxPath = path.resolve("src", "ctx.js");

await fs.rm(HELPER_DECLARATION_PATH, { recursive: true, force: true });

function addIndex(dir: string, file: string) {
const index = indices.get(dir);

if (index) {
index.push(file);
} else {
indices.set(dir, [file]);
}
}

for await (const file of visitAllFiles(HELPER_SRC_PATH)) {
allFiles.push(file);
addIndex(path.dirname(file), file);
}

for (const file of allFiles) {
if (!file.endsWith(".ts")) {
continue;
}

const relativePath = path.relative(HELPER_SRC_PATH, file);

console.log("Building helper:", relativePath);

const targetPath = path.resolve(HELPER_DECLARATION_PATH, relativePath);

const targetDir = path.dirname(targetPath);
const targetFileBase = path.basename(targetPath, ".ts");
const isIndex = targetFileBase === "index";
const targetBase = isIndex ? path.basename(targetDir) : targetFileBase;
await fs.mkdir(targetDir, { recursive: true });

const childModules = isIndex ? indices.get(path.dirname(file)) : [];

if (isIndex) {
indices.delete(path.dirname(file));
}

const contents = await fs.readFile(file, "utf-8");

let childModuleLines =
childModules
?.filter((m) => path.basename(m, ".ts") != "index")
.map((child) => {
const childBase = path.basename(child, ".ts");
return ` await import("./${childBase}.js").then((m) => m.createModule(module));`;
}) ?? [];

if (childModuleLines.length > 0) {
childModuleLines = [" // Child modules", ...childModuleLines, ""];
}

const transformed = [
"// Copyright (c) Microsoft Corporation",
"// Licensed under the MIT license.",
"",
`import { Module } from "${path.relative(targetDir, ctxPath).replace(/\\/g, "/")}";`,
"",
"export let module: Module = undefined as any;",
"",
"const lines = [",
...contents.split(/\r?\n/).map((line) => " " + JSON.stringify(line) + ","),
"];",
"",
"export async function createModule(parent: Module): Promise<Module> {",
" if (module) return module;",
"",
" module = {",
` name: ${JSON.stringify(targetBase)},`,
` cursor: parent.cursor.enter(${JSON.stringify(targetBase)}),`,
" imports: [],",
" declarations: [],",
" };",
"",
...childModuleLines,
" module.declarations.push(lines);",
"",
" parent.declarations.push(module);",
"",
" return module;",
"}",
"",
].join(EOL);

await fs.writeFile(targetPath, transformed);
}

console.log("Building index files.");

for (const [dir, files] of indices.entries()) {
console.log("Building index:", dir);

const relativePath = path.relative(HELPER_SRC_PATH, dir);

const targetPath = path.resolve(HELPER_DECLARATION_PATH, relativePath, "index.ts");

const children = files.map((file) => {
return ` await import("./${path.basename(file, ".ts")}.js").then((m) => m.createModule(module));`;
});

const transformed = [
"// Copyright (c) Microsoft Corporation",
"// Licensed under the MIT license.",
"",
`import { Module } from "${path.relative(path.dirname(targetPath), ctxPath).replace(/\\/g, "/")}";`,
"",
"export let module: Module = undefined as any;",
"",
"export async function createModule(parent: Module): Promise<Module> {",
" if (module) return module;",
"",
" module = {",
` name: ${JSON.stringify(path.basename(dir))},`,
` cursor: parent.cursor.enter(${JSON.stringify(path.basename(dir))}),`,
" imports: [],",
" declarations: [],",
" };",
"",
" // Child modules",
...children,
"",
" parent.declarations.push(module);",
"",
" return module;",
"}",
"",
].join(EOL);

await fs.writeFile(targetPath, transformed);
}
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
4 changes: 4 additions & 0 deletions packages/http-server-javascript/changelog.json
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved
witemple-msft marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@typespec/http-server-javascript",
"entries": []
}
Loading
Loading