Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
cirolosapio committed Mar 18, 2024
0 parents commit 88e4296
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"deno.enable": true
}
12 changes: 12 additions & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"tasks": {
"dev": "deno run --watch main.ts",
"compile": "deno compile --allow-write --allow-read -o mage2postman main.ts"
},
"fmt": {
"lineWidth": 9999,
"semiColons": false,
"singleQuote": true,
"useTabs": true
}
}
20 changes: 20 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 82 additions & 0 deletions functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { join } from 'https://deno.land/[email protected]/path/mod.ts'
import { PostmanItem, Route } from './types.ts'
import { unflatten } from 'npm:flat'
import { destr } from 'npm:destr'

export async function* recursiveReaddir(
path: string,
): AsyncGenerator<string, void> {
for await (const dirEntry of Deno.readDir(path)) {
if (dirEntry.isDirectory) {
yield* recursiveReaddir(join(path, dirEntry.name))
} else if (dirEntry.isFile) {
yield join(path, dirEntry.name)
}
}
}

export function wrap<T>(val: T | T[]) {
return Array.isArray(val) ? val : [val]
}

export function colonToVariable(route: string) {
return route.replace(/:([^/]+)/g, `{{$1}}`)
}

// export function toFolder(path: string) {
// return path.split('/').reduce((res, name) => {
// res[name] =
// return res
// }, {})
// }

export function fixFileName(file: string) {
return file
.replace(/\.\.\//g, '')
.replace('/etc/webapi.xml', '')
.replace('app/vendor/', 'vendor/')
.replace('app/app', 'app')
}

const customer_token: PostmanItem['request']['auth'] = {
type: 'bearer',
bearer: [
{
key: 'token',
type: 'string',
value: '{{customer_token}}',
},
],
}

export function parseRoute(route: Route) {
const url = `{{base_url}}/rest${colonToVariable(route.url)}`
const [host, ...path] = url.split('/')

if (route.auth !== 'anonymous') route.url += ` (${route.auth})`

const item: PostmanItem = {
name: route.url,
request: {
description: `${route.class}@${route.method}`,
method: route.type,
url: {
raw: url,
host: [host],
path,
},
},
}

if (route.data) {
item.request.body = {
mode: 'raw',
raw: JSON.stringify(unflatten(destr(`{ "${route.data}": "<insert_value_here>" }`)), null, 2),
options: { raw: { language: 'json' } },
}
}

if (route.auth === 'self') item.request.auth = customer_token

return item
}
65 changes: 65 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { parseArgs } from 'https://deno.land/[email protected]/cli/parse_args.ts'
import { parse } from 'https://deno.land/x/[email protected]/mod.ts'
import { fixFileName, parseRoute, recursiveReaddir, wrap } from './functions.ts'
import { PostmanCollection, PostmanFolder, Route, XmlRoute } from './types.ts'

let { path, name } = parseArgs(Deno.args, {
string: ['path', 'name'],
})

if (!name) name = (path ?? Deno.cwd()).split('/').at(-1)!
if (!path) path = '.'

const time = performance.now()

const files: Record<string, Route[]> = {}
for await (const file of recursiveReaddir(path)) {
if (file.endsWith('webapi.xml') && !file.startsWith('../../app/dev')) {
const content = new TextDecoder().decode(await Deno.readFile(file))
const { route } = parse(content).routes as unknown as { route: XmlRoute | XmlRoute[] }
const key = fixFileName(file)
files[key] = []
wrap(route).forEach((r) => {
r && files[key].push({
class: r.service ? r.service['@class'] : undefined,
type: r['@method'],
method: r.service ? r.service['@method'] : undefined,
url: r['@url'],
data: r.data?.parameter ? r.data.parameter['@name'] : undefined,
auth: r.resources?.resource ? r.resources.resource['@ref'] : undefined,
})
})
}
}

const sorted: Record<string, Route[]> = {}
for (const key of Object.keys(files).sort()) sorted[key] = files[key]

const info: PostmanCollection['info'] = {
name,
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
}

const collection = Object.entries(sorted).reduce((res, [file, routes]) => {
let current = res.item

const parts = file.split('/')

parts.forEach((name, idx) => {
const existing = current.find((item) => item.name === name) as PostmanFolder | undefined

if (existing) current = existing.item
else {
const newItem: PostmanFolder = { name, item: [] }
if (parts.length - 1 === idx) newItem.item.push(...routes.map((route) => parseRoute(route)))
current.push(newItem)
current = newItem.item
}
})

return res
}, { info, item: [] } as PostmanCollection)

await Deno.writeFile(`${info.name}.postman_collection.json`, new TextEncoder().encode(JSON.stringify(collection)))

console.log(`done in ${performance.now() - time} ms`)
94 changes: 94 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
export interface XmlRoute {
'@url': string
'@method': 'GET' | 'POST' | 'PUT'
service?: {
'@class': string
'@method': string
}
resources: {
resource: {
'@ref': string
}
}
data?: {
parameter?: {
'@name': string
}
}
}

export interface Route {
type: XmlRoute['@method']
url: string
class?: string
method?: string
data?: string
auth?: string
}

interface PostmanEvent {
listen: string
script: {
type: string
exec: string[]
}
}

interface KeyValue {
key: string
value: string
}

export interface PostmanItem {
name: string
event?: PostmanEvent[]
response?: []
request: {
auth?: {
type: 'bearer'
bearer: {
key: 'token'
value: '{{customer_token}}' | '{{admin_token}}'
type: 'string'
}[]
}
method: XmlRoute['@method']
header?: string[]
description?: string
body?: {
mode: 'raw'
raw: string
options?: {
raw: {
language: 'json'
}
}
}
url: {
raw: string
host: string[]
path: string[]
query?: KeyValue[]
}
}
}

type Folder<T> = {
name: string
item: T[]
}

export type PostmanFolder = Folder<PostmanItem>

export interface PostmanCollection {
event?: PostmanEvent[]
variabile?: KeyValue[]
info: {
name: string
_postman_id?: string
description?: string
schema?: string
_exporter_id?: string
}
item: (PostmanItem | PostmanFolder)[]
}

0 comments on commit 88e4296

Please sign in to comment.