snapshot of https://github.com/mountain-loop/yaak.git (main, 2026-09-23; blobs > 131072B omitted)
This commit is contained in:
13
plugins/importer-postman-environment/package.json
Normal file
13
plugins/importer-postman-environment/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@yaak/importer-postman-environment",
|
||||
"displayName": "Postman Environment Importer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "Import environments from Postman",
|
||||
"main": "./build/index.js",
|
||||
"scripts": {
|
||||
"build": "yaakcli build",
|
||||
"dev": "yaakcli dev",
|
||||
"test": "vp test --run tests"
|
||||
}
|
||||
}
|
||||
135
plugins/importer-postman-environment/src/index.ts
Normal file
135
plugins/importer-postman-environment/src/index.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
/* oxlint-disable no-base-to-string */
|
||||
import type {
|
||||
Context,
|
||||
Environment,
|
||||
PartialImportResources,
|
||||
PluginDefinition,
|
||||
Workspace,
|
||||
} from "@yaakapp/api";
|
||||
import type { ImportPluginResponse } from "@yaakapp/api/lib/plugins/ImporterPlugin";
|
||||
|
||||
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
|
||||
|
||||
interface ExportResources {
|
||||
workspaces: AtLeast<Workspace, "name" | "id" | "model">[];
|
||||
environments: AtLeast<Environment, "name" | "id" | "model" | "workspaceId">[];
|
||||
}
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
importer: {
|
||||
name: "Postman Environment",
|
||||
description: "Import postman environment exports",
|
||||
onImport(_ctx: Context, args: { text: string }) {
|
||||
return convertPostmanEnvironment(args.text);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function convertPostmanEnvironment(contents: string): ImportPluginResponse | undefined {
|
||||
const root = parseJSONToRecord(contents);
|
||||
if (root == null) return;
|
||||
|
||||
// Validate that it looks like a Postman Environment export
|
||||
const values = toArray<{
|
||||
key?: string;
|
||||
value?: unknown;
|
||||
enabled?: boolean;
|
||||
description?: string;
|
||||
type?: string;
|
||||
}>(root.values);
|
||||
const scope = root._postman_variable_scope;
|
||||
const hasEnvMarkers = typeof scope === "string";
|
||||
|
||||
if (values.length === 0 || (!hasEnvMarkers && typeof root.name !== "string")) {
|
||||
// Not a Postman environment file, skip
|
||||
return;
|
||||
}
|
||||
|
||||
const exportResources: ExportResources = {
|
||||
workspaces: [],
|
||||
environments: [],
|
||||
};
|
||||
|
||||
const envVariables = values
|
||||
.map((v) => ({
|
||||
enabled: v.enabled ?? true,
|
||||
name: String(v.key ?? ""),
|
||||
value: String(v.value),
|
||||
description: v.description ? String(v.description) : null,
|
||||
}))
|
||||
.filter((v) => v.name.length > 0);
|
||||
|
||||
const environment: ExportResources["environments"][0] = {
|
||||
model: "environment",
|
||||
id: generateId("environment"),
|
||||
name: root.name ? String(root.name) : "Environment",
|
||||
workspaceId: "CURRENT_WORKSPACE",
|
||||
parentModel: "environment",
|
||||
parentId: null,
|
||||
variables: envVariables,
|
||||
};
|
||||
exportResources.environments.push(environment);
|
||||
|
||||
const resources = deleteUndefinedAttrs(
|
||||
convertTemplateSyntax(exportResources),
|
||||
) as PartialImportResources;
|
||||
|
||||
return { resources };
|
||||
}
|
||||
|
||||
function parseJSONToRecord<T>(jsonStr: string): Record<string, T> | null {
|
||||
try {
|
||||
return toRecord(JSON.parse(jsonStr));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function toRecord<T>(value: unknown): Record<string, T> {
|
||||
if (value && typeof value === "object" && !Array.isArray(value)) {
|
||||
return value as Record<string, T>;
|
||||
}
|
||||
return {} as Record<string, T>;
|
||||
}
|
||||
|
||||
function toArray<T>(value: unknown): T[] {
|
||||
if (Object.prototype.toString.call(value) === "[object Array]") return value as T[];
|
||||
return [] as T[];
|
||||
}
|
||||
|
||||
/** Recursively render all nested object properties */
|
||||
function convertTemplateSyntax<T>(obj: T): T {
|
||||
if (typeof obj === "string") {
|
||||
return obj.replace(/{{\s*(_\.)?([^}]*)\s*}}/g, (_m, _dot, expr) => `\${[${expr.trim()}]}`) as T;
|
||||
}
|
||||
if (Array.isArray(obj) && obj != null) {
|
||||
return obj.map(convertTemplateSyntax) as T;
|
||||
}
|
||||
if (typeof obj === "object" && obj != null) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj as Record<string, unknown>).map(([k, v]) => [k, convertTemplateSyntax(v)]),
|
||||
) as T;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function deleteUndefinedAttrs<T>(obj: T): T {
|
||||
if (Array.isArray(obj) && obj != null) {
|
||||
return obj.map(deleteUndefinedAttrs) as T;
|
||||
}
|
||||
if (typeof obj === "object" && obj != null) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj as Record<string, unknown>)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.map(([k, v]) => [k, deleteUndefinedAttrs(v)]),
|
||||
) as T;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
const idCount: Partial<Record<string, number>> = {};
|
||||
|
||||
function generateId(model: string): string {
|
||||
idCount[model] = (idCount[model] ?? -1) + 1;
|
||||
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
|
||||
}
|
||||
27
plugins/importer-postman-environment/tests/fixtures/environment.input.json
vendored
Normal file
27
plugins/importer-postman-environment/tests/fixtures/environment.input.json
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"id": "123",
|
||||
"name": "My Environment",
|
||||
"values": [
|
||||
{
|
||||
"key": "baseUrl",
|
||||
"value": "https://api.example.com",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{ access_token }}",
|
||||
"type": "default",
|
||||
"description": "Access token for the API.",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "disabled",
|
||||
"type": "secret",
|
||||
"value": "hello",
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_using": "PostmanRuntime/1.0.0"
|
||||
}
|
||||
35
plugins/importer-postman-environment/tests/fixtures/environment.output.json
vendored
Normal file
35
plugins/importer-postman-environment/tests/fixtures/environment.output.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"resources": {
|
||||
"workspaces": [],
|
||||
"environments": [
|
||||
{
|
||||
"id": "GENERATE_ID::ENVIRONMENT_0",
|
||||
"model": "environment",
|
||||
"name": "My Environment",
|
||||
"variables": [
|
||||
{
|
||||
"enabled": true,
|
||||
"description": null,
|
||||
"name": "baseUrl",
|
||||
"value": "https://api.example.com"
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"description": "Access token for the API.",
|
||||
"name": "token",
|
||||
"value": "${[access_token]}"
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"description": null,
|
||||
"name": "disabled",
|
||||
"value": "hello"
|
||||
}
|
||||
],
|
||||
"workspaceId": "CURRENT_WORKSPACE",
|
||||
"parentId": null,
|
||||
"parentModel": "environment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
22
plugins/importer-postman-environment/tests/index.test.ts
Normal file
22
plugins/importer-postman-environment/tests/index.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { describe, expect, test } from "vite-plus/test";
|
||||
import { convertPostmanEnvironment } from "../src";
|
||||
|
||||
describe("importer-postman-environment", () => {
|
||||
const p = path.join(__dirname, "fixtures");
|
||||
const fixtures = fs.readdirSync(p);
|
||||
|
||||
for (const fixture of fixtures) {
|
||||
if (fixture.includes(".output")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
test(`Imports ${fixture}`, () => {
|
||||
const contents = fs.readFileSync(path.join(p, fixture), "utf-8");
|
||||
const expected = fs.readFileSync(path.join(p, fixture.replace(".input", ".output")), "utf-8");
|
||||
const result = convertPostmanEnvironment(contents);
|
||||
expect(result).toEqual(JSON.parse(expected));
|
||||
});
|
||||
}
|
||||
});
|
||||
3
plugins/importer-postman-environment/tsconfig.json
Normal file
3
plugins/importer-postman-environment/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
||||
Reference in New Issue
Block a user