Skip to content

Commit

Permalink
fix #46: Handle most of quoted property name issues (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
Embraser01 authored Oct 25, 2023
1 parent 5202654 commit d4fdd18
Show file tree
Hide file tree
Showing 17 changed files with 198 additions and 23 deletions.
41 changes: 36 additions & 5 deletions .pnp.cjs

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

Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions packages/typoas-generator/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['/node_modules/', '/lib/'],
};
7 changes: 6 additions & 1 deletion packages/typoas-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"prepack": "tsc",
"test:jest": "jest",
"test:types": "tsc --noEmit"
"test:types": "tsc --noEmit",
"generate-identifier-regexp": "ts-node ./scripts/generate-identifier-regexp.ts"
},
"dependencies": {
"lodash": "^4.17.21",
Expand All @@ -22,9 +23,13 @@
"@jest/globals": "^29.5.0",
"@types/lodash": "^4.14.194",
"@types/node": "^20.2.3",
"@types/regenerate": "^1.4.2",
"@unicode/unicode-9.0.0": "^1.5.2",
"jest": "^29.5.0",
"jest-environment-node": "^29.5.0",
"regenerate": "^1.4.2",
"ts-jest": "^29.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
},
"files": [
Expand Down
51 changes: 51 additions & 0 deletions packages/typoas-generator/scripts/generate-identifier-regexp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Based on https://gist.github.com/mathiasbynens/6334847 by @mathias
*/
import { writeFile } from 'node:fs/promises';
import regenerate from 'regenerate';

// Which Unicode version should be used
const version = '9.0.0';

// Set up a shorthand function to import Unicode data.
async function get(what: string): Promise<number[]> {
const { default: codePoints } = await import(
`@unicode/unicode-${version}/${what}/code-points.js`
);
return codePoints;
}

async function main() {
// Get the Unicode properties needed to construct the ES6 regex.
const ID_Start = await get('Binary_Property/ID_Start');
const ID_Continue = await get('Binary_Property/ID_Continue');
const Other_ID_Start = await get('Binary_Property/Other_ID_Start');

// http://ecma-international.org/ecma-262/6.0/#sec-identifier-names-static-semantics-early-errors
// http://unicode.org/reports/tr31/#Default_Identifier_Syntax
// https://bugs.ecmascript.org/show_bug.cgi?id=2717#c0
const identifierStart = regenerate(ID_Start)
// Note: this already includes `Other_ID_Start`. http://git.io/wRCAfQ
.add('$', '_');
const identifierPart = regenerate(ID_Continue)
// Note: `ID_Continue` already includes `Other_ID_Continue`. http://git.io/wRCAfQ
.add(Other_ID_Start)
.add('$', '_', '\u200C', '\u200D');

const fileContent = `/* eslint-disable no-misleading-character-class,no-useless-escape */
// This file is generated by scripts/generate-identifier-regexp.ts
// Do not edit it manually.
export const identifierStartRegexp =
/${identifierStart.toString()}/;
export const identifierPartRegexp =
/${identifierPart.toString()}/;
export const es6IdentifierRegexp =
/^(?:${identifierStart.toString()})(?:${identifierPart.toString()})*$/;
`;

await writeFile('./src/generator/utils/identifier-regexps.ts', fileContent);
}

main();
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
getParameterName,
isParameterRequired,
} from '../../components/parameters';
import { hasUnsupportedIdentifierChar } from '../../utils/operation-name';
import { isInvalidES6IdentifierName } from '../../utils/operation-name';
import { createSchemaTypeFromRequestBody } from '../../components/request-bodies';
import { GlobalParameters } from './types';
import { createSchemaTypeFromResponse } from '../../components/responses';
Expand Down Expand Up @@ -61,7 +61,7 @@ export function createOperationDeclaration(

return factory.createPropertySignature(
undefined,
hasUnsupportedIdentifierChar(name)
isInvalidES6IdentifierName(name)
? factory.createStringLiteral(name, true)
: factory.createIdentifier(name),
isParameterRequired(p, ctx)
Expand Down
10 changes: 5 additions & 5 deletions packages/typoas-generator/src/generator/api/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
createConfigTypeFromSecurityScheme,
createRuntimeSecurityClass,
} from '../components/security-scheme';
import { hasUnsupportedIdentifierChar } from '../utils/operation-name';
import { isInvalidES6IdentifierName } from '../utils/operation-name';

export const AUTH_TYPE_NAME = 'AuthMethods';

Expand All @@ -27,7 +27,7 @@ export function createAuthMethodsType(
Object.entries(securitySchemes).map(([name, sec]) =>
factory.createPropertySignature(
undefined,
hasUnsupportedIdentifierChar(name)
isInvalidES6IdentifierName(name)
? factory.createStringLiteral(name, true)
: factory.createIdentifier(name),
factory.createToken(SyntaxKind.QuestionToken),
Expand Down Expand Up @@ -70,11 +70,11 @@ export function createConfigureAuthFunction(
factory.createObjectLiteralExpression(
Object.entries(securitySchemes).map(([name, sec]) =>
factory.createPropertyAssignment(
hasUnsupportedIdentifierChar(name)
isInvalidES6IdentifierName(name)
? factory.createStringLiteral(name, true)
: factory.createIdentifier(name),
factory.createLogicalAnd(
hasUnsupportedIdentifierChar(name)
isInvalidES6IdentifierName(name)
? factory.createElementAccessChain(
factory.createIdentifier('params'),
factory.createToken(SyntaxKind.QuestionDotToken),
Expand All @@ -87,7 +87,7 @@ export function createConfigureAuthFunction(
),
createRuntimeSecurityClass(
sec,
hasUnsupportedIdentifierChar(name)
isInvalidES6IdentifierName(name)
? factory.createElementAccessExpression(
factory.createIdentifier('params'),
factory.createStringLiteral(name),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ exports[`create type from schema should handle object schema without properties
}"
`;

exports[`create type from schema should handle objects with special named properties 1`] = `
"{
'1'?: number;
'^Test^'?: string;
await?: string;
b?: number;
ʱ?: number;
_1?: number;
'page[number]'?: number;
}"
`;

exports[`create type from schema should handle primitive boolean enums 1`] = `"true"`;

exports[`create type from schema should handle primitive boolean schema 1`] = `"boolean"`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,25 @@ describe('create type from schema', () => {
expect(getStringFromNode(node)).toMatchSnapshot();
});

it('should handle objects with special named properties', () => {
const schema: SchemaObject = {
type: 'object',
required: ['a'],
properties: {
'^Test^': { type: 'string' },
await: { type: 'string' },
b: { type: 'number' },
ʱ: { type: 'number' },
_1: { type: 'number' },
1: { type: 'number' },
'page[number]': { type: 'number' },
},
};

const node = createTypeFromSchema(schema, new Context());
expect(getStringFromNode(node)).toMatchSnapshot();
});

describe('with complex object', () => {
it('should create nested objects', () => {
const schema: SchemaObject = {
Expand Down
Loading

0 comments on commit d4fdd18

Please sign in to comment.