Skip to content

chore: doc specs location and scripts cleanup [skip-bc] #4227

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

Merged
merged 15 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"scripts:build": "yarn workspace scripts build",
"scripts:lint": "yarn workspace scripts lint",
"scripts:test": "yarn workspace scripts test",
"specs:fix": "eslint --ext=yml specs/$0 --fix",
"specs:lint": "eslint --ext=yml specs/$0",
"specs:fix": "eslint --ext=yml $0 --fix",
"specs:lint": "eslint --ext=yml $0",
"website": "cd website && yarn start",
"website:build": "bash scripts/website/build.sh"
},
Expand Down
4 changes: 2 additions & 2 deletions scripts/ci/codegen/pushToRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ async function handleSpecFiles(spec: SpecsToPush, tempGitDir: string): Promise<v
await run(`rm -rf ${pathToSpecs}/* || true`);
await run(`cp ${toAbsolutePath('specs/bundled/README.md')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('specs/major-breaking-changes-rename.json')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('specs/bundled/*.doc.yml')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('config/clients.config.json')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('docs/bundled/*.json')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('docs/bundled/*.yml')} ${pathToSpecs}`);
await run(`cp ${toAbsolutePath('docs/versions-history-with-sla-and-support-policy.json')} ${pathToSpecs}`);
// adblock extensions ban words like `analytics` so we use a different file name just so the doc dans render it
await run(`mv ${pathToSpecs}/analytics.doc.yml ${pathToSpecs}/searchstats.doc.yml`);
await run(`mv ${pathToSpecs}/analytics.yml ${pathToSpecs}/searchstats.yml`);
}

async function handleGuideFiles(guide: GuidesToPush, tempGitDir: string): Promise<void> {
Expand Down
149 changes: 35 additions & 114 deletions scripts/specs/__tests__/snippets.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { describe, expect, it } from 'vitest';

import { transformCodeSamplesToGuideMethods } from '../snippets.js';
import { SnippetSamples } from '../types.js';
import { parseCodeSamples } from '../snippets.js';
import { CodeSamples } from '../types.js';

describe('init', () => {
it('parses a multi line import', () => {
expect(
JSON.parse(
transformCodeSamplesToGuideMethods({
csharp: {
foo: {
default: `
JSON.stringify(
parseCodeSamples({
foo: {
default: `
// Initialize the client
var client = new QuerySuggestionsClient(
new QuerySuggestionsConfig("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION")
Expand Down Expand Up @@ -40,53 +39,26 @@ var response = await client.CreateConfigAsync(
);
// >LOG
`,
},
},
} as unknown as SnippetSamples),
} as unknown as CodeSamples),
null,
2,
),
).toMatchInlineSnapshot(`
{
"csharp": {
"foo": {
"default": "var response = await client.CreateConfigAsync(
new ConfigurationWithIndex
{
IndexName = "<YOUR_INDEX_NAME>",
SourceIndices = new List<SourceIndex>
{
new SourceIndex
{
IndexName = "<YOUR_INDEX_NAME>",
Facets = new List<Facet> { new Facet { Attribute = "test" } },
Generate = new List<List<string>>
{
new List<string> { "facetA", "facetB" },
new List<string> { "facetC" },
},
},
},
Languages = new Languages(new List<string> { "french" }),
Exclude = new List<string> { "test" },
"{
"foo": {
"default": "\\n // Initialize the client\\nvar client = new QuerySuggestionsClient(\\n new QuerySuggestionsConfig(\\"YOUR_APP_ID\\", \\"YOUR_API_KEY\\", \\"YOUR_APP_ID_REGION\\")\\n);\\n\\n// Call the API\\nvar response = await client.CreateConfigAsync(\\n new ConfigurationWithIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n SourceIndices = new List<SourceIndex>\\n {\\n new SourceIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n Facets = new List<Facet> { new Facet { Attribute = \\"test\\" } },\\n Generate = new List<List<string>>\\n {\\n new List<string> { \\"facetA\\", \\"facetB\\" },\\n new List<string> { \\"facetC\\" },\\n },\\n },\\n },\\n Languages = new Languages(new List<string> { \\"french\\" }),\\n Exclude = new List<string> { \\"test\\" },\\n }\\n);\\n// >LOG\\n "
}
);",
},
"init": {
"default": "var client = new QuerySuggestionsClient(
new QuerySuggestionsConfig("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION")
);",
},
},
}
}"
`);
});

it('parses a single line import', () => {
expect(
JSON.parse(
transformCodeSamplesToGuideMethods({
csharp: {
foo: {
default: `
JSON.stringify(
parseCodeSamples({
foo: {
default: `
// Initialize the client
var client = new QuerySuggestionsClient(new Client("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION"));

Expand Down Expand Up @@ -114,53 +86,28 @@ var response = await client.CreateConfigAsync(
);
// >LOG
`,
},
},
} as unknown as SnippetSamples),
} as unknown as CodeSamples),
null,
2,
),
).toMatchInlineSnapshot(`
{
"csharp": {
"foo": {
"default": "var response = await client.CreateConfigAsync(
new ConfigurationWithIndex
{
IndexName = "<YOUR_INDEX_NAME>",
SourceIndices = new List<SourceIndex>
{
new SourceIndex
{
IndexName = "<YOUR_INDEX_NAME>",
Facets = new List<Facet> { new Facet { Attribute = "test" } },
Generate = new List<List<string>>
{
new List<string> { "facetA", "facetB" },
new List<string> { "facetC" },
},
},
},
Languages = new Languages(new List<string> { "french" }),
Exclude = new List<string> { "test" },
"{
"foo": {
"default": "\\n // Initialize the client\\nvar client = new QuerySuggestionsClient(new Client(\\"YOUR_APP_ID\\", \\"YOUR_API_KEY\\", \\"YOUR_APP_ID_REGION\\"));\\n\\n// Call the API\\nvar response = await client.CreateConfigAsync(\\n new ConfigurationWithIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n SourceIndices = new List<SourceIndex>\\n {\\n new SourceIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n Facets = new List<Facet> { new Facet { Attribute = \\"test\\" } },\\n Generate = new List<List<string>>\\n {\\n new List<string> { \\"facetA\\", \\"facetB\\" },\\n new List<string> { \\"facetC\\" },\\n },\\n },\\n },\\n Languages = new Languages(new List<string> { \\"french\\" }),\\n Exclude = new List<string> { \\"test\\" },\\n }\\n);\\n// >LOG\\n "
}
);",
},
"init": {
"default": "var client = new QuerySuggestionsClient(new Client("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION"));",
},
},
}
}"
`);
});
});

describe('initialize', () => {
it("doesn't stop at `client`", () => {
expect(
JSON.parse(
transformCodeSamplesToGuideMethods({
csharp: {
foo: {
default: `
JSON.stringify(
parseCodeSamples({
foo: {
default: `
// Initialize the client foo bar BAAAAAAAAAAAAAAAAAAAAAZ
var client = new QuerySuggestionsClient(
new QuerySuggestionsConfig("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION")
Expand Down Expand Up @@ -190,43 +137,17 @@ var response = await client.CreateConfigAsync(
);
// >LOG
`,
},
},
} as unknown as SnippetSamples),
} as unknown as CodeSamples),
null,
2,
),
).toMatchInlineSnapshot(`
{
"csharp": {
"foo": {
"default": "var response = await client.CreateConfigAsync(
new ConfigurationWithIndex
{
IndexName = "<YOUR_INDEX_NAME>",
SourceIndices = new List<SourceIndex>
{
new SourceIndex
{
IndexName = "<YOUR_INDEX_NAME>",
Facets = new List<Facet> { new Facet { Attribute = "test" } },
Generate = new List<List<string>>
{
new List<string> { "facetA", "facetB" },
new List<string> { "facetC" },
},
},
},
Languages = new Languages(new List<string> { "french" }),
Exclude = new List<string> { "test" },
"{
"foo": {
"default": "\\n // Initialize the client foo bar BAAAAAAAAAAAAAAAAAAAAAZ\\nvar client = new QuerySuggestionsClient(\\n new QuerySuggestionsConfig(\\"YOUR_APP_ID\\", \\"YOUR_API_KEY\\", \\"YOUR_APP_ID_REGION\\")\\n);\\n\\n// Call the API\\nvar response = await client.CreateConfigAsync(\\n new ConfigurationWithIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n SourceIndices = new List<SourceIndex>\\n {\\n new SourceIndex\\n {\\n IndexName = \\"<YOUR_INDEX_NAME>\\",\\n Facets = new List<Facet> { new Facet { Attribute = \\"test\\" } },\\n Generate = new List<List<string>>\\n {\\n new List<string> { \\"facetA\\", \\"facetB\\" },\\n new List<string> { \\"facetC\\" },\\n },\\n },\\n },\\n Languages = new Languages(new List<string> { \\"french\\" }),\\n Exclude = new List<string> { \\"test\\" },\\n }\\n);\\n// >LOG\\n "
}
);",
},
"init": {
"default": "var client = new QuerySuggestionsClient(
new QuerySuggestionsConfig("YOUR_APP_ID", "YOUR_API_KEY", "YOUR_APP_ID_REGION")
);",
},
},
}
}"
`);
});
});
68 changes: 18 additions & 50 deletions scripts/specs/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { HarRequest, HTTPSnippet } from 'httpsnippet';
import yaml from 'js-yaml';

import { Cache } from '../cache.js';
import { exists, GENERATORS, run, toAbsolutePath } from '../common.js';
import { GENERATORS, run, toAbsolutePath } from '../common.js';
import { createSpinner } from '../spinners.js';
import type { Spec } from '../types.js';

import { getCodeSampleLabel, transformCodeSamplesToGuideMethods, transformSnippetsToCodeSamples } from './snippets.js';
import type { SnippetSamples } from './types.js';
import { getCodeSampleLabel, parseCodeSamples, transformGeneratedSnippetsToCodeSamples } from './snippets.js';

export async function lintCommon(useCache: boolean): Promise<void> {
const spinner = createSpinner('linting common spec');
Expand All @@ -27,7 +26,7 @@ export async function lintCommon(useCache: boolean): Promise<void> {
return;
}

await run('yarn specs:lint common');
await run('yarn specs:lint specs/common');

if (useCache) {
spinner.text = 'storing common spec cache';
Expand All @@ -37,48 +36,26 @@ export async function lintCommon(useCache: boolean): Promise<void> {
spinner.succeed();
}

/*
* This function will transform properties in the bundle depending on the context.
* E.g:
* - Check tags definition
* - Add name of the client in tags
* - Remove unecessary punctuation for documentation
* - etc...
*/
export async function transformBundle({
bundledPath,
docs,
clientName,
alias,
}: {
bundledPath: string;
docs: boolean;
clientName: string;
alias?: string;
}): Promise<void> {
if (!(await exists(bundledPath))) {
throw new Error(`Bundled file not found ${bundledPath}.`);
}
export async function bundleSpecsForClient(bundledPath: string, clientName: string): Promise<void> {
const bundledSpec = yaml.load(await fsp.readFile(bundledPath, 'utf8')) as Spec;

Object.values(bundledSpec.paths).forEach((pathMethods) => {
Object.values(pathMethods).forEach((specMethod) => (specMethod.tags = [clientName]));
});

await fsp.writeFile(bundledPath, yaml.dump(bundledSpec, { noRefs: true }));
}

export async function bundleSpecsForDoc(bundledPath: string, clientName: string): Promise<void> {
const bundledSpec = yaml.load(await fsp.readFile(bundledPath, 'utf8')) as Spec;
const harRequests = await oas2har.oas2har(bundledSpec as any, { includeVendorExamples: true });
const tagsDefinitions = bundledSpec.tags;
const snippetSamples = docs ? await transformSnippetsToCodeSamples(clientName) : ({} as SnippetSamples);
const codeSamples = await transformGeneratedSnippetsToCodeSamples(clientName);

if (docs) {
const snippets = transformCodeSamplesToGuideMethods(JSON.parse(JSON.stringify(snippetSamples)));
await fsp.writeFile(toAbsolutePath(`docs/bundled/${clientName}-snippets.json`), snippets);
}
parseCodeSamples(JSON.parse(JSON.stringify(codeSamples)));

for (const [pathKey, pathMethods] of Object.entries(bundledSpec.paths)) {
for (const [method, specMethod] of Object.entries(pathMethods)) {
if (!docs) {
// In the main bundle we need to have only the clientName
// because open-api-generator will use this to determine the name of the client
specMethod.tags = [clientName];
continue;
}

if (specMethod['x-helper']) {
delete bundledSpec.paths[pathKey];
break;
Expand All @@ -94,11 +71,11 @@ export async function transformBundle({
specMethod['x-codeSamples'] = [];
}

if (snippetSamples[gen.language][specMethod.operationId]) {
if (codeSamples[gen.language][specMethod.operationId]) {
specMethod['x-codeSamples'].push({
lang: gen.language,
label: getCodeSampleLabel(gen.language),
source: Object.values(snippetSamples[gen.language][specMethod.operationId])[0],
source: Object.values(codeSamples[gen.language][specMethod.operationId])[0],
});
}
}
Expand Down Expand Up @@ -142,12 +119,6 @@ export async function transformBundle({
);
}

if (alias && tag === alias) {
throw new Error(
`Tag name "${tag} for operation ${specMethod.operationId} must be different from alias ${alias}`,
);
}

const tagExists = tagsDefinitions ? tagsDefinitions.find((t) => t.name === tag) : null;
if (!tagExists) {
throw new Error(
Expand All @@ -158,8 +129,5 @@ export async function transformBundle({
}
}

await fsp.writeFile(
docs ? toAbsolutePath(`specs/bundled/${clientName}.doc.yml`) : bundledPath,
yaml.dump(bundledSpec, { noRefs: true }),
);
await fsp.writeFile(toAbsolutePath(`docs/bundled/${clientName}.yml`), yaml.dump(bundledSpec, { noRefs: true }));
}
Loading