Erster Commit
This commit is contained in:
+278
@@ -0,0 +1,278 @@
|
||||
"use strict";
|
||||
// Copyright 2021-2024 Buf Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.safeIdentifier = exports.safeObjectProperty = exports.findEnumSharedPrefix = exports.fieldJsonName = exports.localOneofName = exports.localFieldName = exports.localName = void 0;
|
||||
/**
|
||||
* Returns the name of a protobuf element in generated code.
|
||||
*
|
||||
* Field names - including oneofs - are converted to lowerCamelCase. For
|
||||
* messages, enumerations and services, the package name is stripped from
|
||||
* the type name. For nested messages and enumerations, the names are joined
|
||||
* with an underscore. For methods, the first character is made lowercase.
|
||||
*/
|
||||
function localName(desc) {
|
||||
switch (desc.kind) {
|
||||
case "field":
|
||||
return localFieldName(desc.name, desc.oneof !== undefined);
|
||||
case "oneof":
|
||||
return localOneofName(desc.name);
|
||||
case "enum":
|
||||
case "message":
|
||||
case "service":
|
||||
case "extension": {
|
||||
const pkg = desc.file.proto.package;
|
||||
const offset = pkg === undefined ? 0 : pkg.length + 1;
|
||||
const name = desc.typeName.substring(offset).replace(/\./g, "_");
|
||||
// For services, we only care about safe identifiers, not safe object properties,
|
||||
// but we have shipped v1 with a bug that respected object properties, and we
|
||||
// do not want to introduce a breaking change, so we continue to escape for
|
||||
// safe object properties.
|
||||
// See https://github.com/bufbuild/protobuf-es/pull/391
|
||||
return (0, exports.safeObjectProperty)((0, exports.safeIdentifier)(name));
|
||||
}
|
||||
case "enum_value": {
|
||||
let name = desc.name;
|
||||
const sharedPrefix = desc.parent.sharedPrefix;
|
||||
if (sharedPrefix !== undefined) {
|
||||
name = name.substring(sharedPrefix.length);
|
||||
}
|
||||
return (0, exports.safeObjectProperty)(name);
|
||||
}
|
||||
case "rpc": {
|
||||
let name = desc.name;
|
||||
if (name.length == 0) {
|
||||
return name;
|
||||
}
|
||||
name = name[0].toLowerCase() + name.substring(1);
|
||||
return (0, exports.safeObjectProperty)(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.localName = localName;
|
||||
/**
|
||||
* Returns the name of a field in generated code.
|
||||
*/
|
||||
function localFieldName(protoName, inOneof) {
|
||||
const name = protoCamelCase(protoName);
|
||||
if (inOneof) {
|
||||
// oneof member names are not properties, but values of the `case` property.
|
||||
return name;
|
||||
}
|
||||
return (0, exports.safeObjectProperty)(safeMessageProperty(name));
|
||||
}
|
||||
exports.localFieldName = localFieldName;
|
||||
/**
|
||||
* Returns the name of a oneof group in generated code.
|
||||
*/
|
||||
function localOneofName(protoName) {
|
||||
return localFieldName(protoName, false);
|
||||
}
|
||||
exports.localOneofName = localOneofName;
|
||||
/**
|
||||
* Returns the JSON name for a protobuf field, exactly like protoc does.
|
||||
*/
|
||||
exports.fieldJsonName = protoCamelCase;
|
||||
/**
|
||||
* Finds a prefix shared by enum values, for example `MY_ENUM_` for
|
||||
* `enum MyEnum {MY_ENUM_A=0; MY_ENUM_B=1;}`.
|
||||
*/
|
||||
function findEnumSharedPrefix(enumName, valueNames) {
|
||||
const prefix = camelToSnakeCase(enumName) + "_";
|
||||
for (const name of valueNames) {
|
||||
if (!name.toLowerCase().startsWith(prefix)) {
|
||||
return undefined;
|
||||
}
|
||||
const shortName = name.substring(prefix.length);
|
||||
if (shortName.length == 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (/^\d/.test(shortName)) {
|
||||
// identifiers must not start with numbers
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
exports.findEnumSharedPrefix = findEnumSharedPrefix;
|
||||
/**
|
||||
* Converts lowerCamelCase or UpperCamelCase into lower_snake_case.
|
||||
* This is used to find shared prefixes in an enum.
|
||||
*/
|
||||
function camelToSnakeCase(camel) {
|
||||
return (camel.substring(0, 1) + camel.substring(1).replace(/[A-Z]/g, (c) => "_" + c)).toLowerCase();
|
||||
}
|
||||
/**
|
||||
* Converts snake_case to protoCamelCase according to the convention
|
||||
* used by protoc to convert a field name to a JSON name.
|
||||
*/
|
||||
function protoCamelCase(snakeCase) {
|
||||
let capNext = false;
|
||||
const b = [];
|
||||
for (let i = 0; i < snakeCase.length; i++) {
|
||||
let c = snakeCase.charAt(i);
|
||||
switch (c) {
|
||||
case "_":
|
||||
capNext = true;
|
||||
break;
|
||||
case "0":
|
||||
case "1":
|
||||
case "2":
|
||||
case "3":
|
||||
case "4":
|
||||
case "5":
|
||||
case "6":
|
||||
case "7":
|
||||
case "8":
|
||||
case "9":
|
||||
b.push(c);
|
||||
capNext = false;
|
||||
break;
|
||||
default:
|
||||
if (capNext) {
|
||||
capNext = false;
|
||||
c = c.toUpperCase();
|
||||
}
|
||||
b.push(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return b.join("");
|
||||
}
|
||||
/**
|
||||
* Names that cannot be used for identifiers, such as class names,
|
||||
* but _can_ be used for object properties.
|
||||
*/
|
||||
const reservedIdentifiers = new Set([
|
||||
// ECMAScript 2015 keywords
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"export",
|
||||
"extends",
|
||||
"false",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"null",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
// ECMAScript 2015 future reserved keywords
|
||||
"enum",
|
||||
"implements",
|
||||
"interface",
|
||||
"let",
|
||||
"package",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"static",
|
||||
// Class name cannot be 'Object' when targeting ES5 with module CommonJS
|
||||
"Object",
|
||||
// TypeScript keywords that cannot be used for types (as opposed to variables)
|
||||
"bigint",
|
||||
"number",
|
||||
"boolean",
|
||||
"string",
|
||||
"object",
|
||||
// Identifiers reserved for the runtime, so we can generate legible code
|
||||
"globalThis",
|
||||
"Uint8Array",
|
||||
"Partial",
|
||||
]);
|
||||
/**
|
||||
* Names that cannot be used for object properties because they are reserved
|
||||
* by built-in JavaScript properties.
|
||||
*/
|
||||
const reservedObjectProperties = new Set([
|
||||
// names reserved by JavaScript
|
||||
"constructor",
|
||||
"toString",
|
||||
"toJSON",
|
||||
"valueOf",
|
||||
]);
|
||||
/**
|
||||
* Names that cannot be used for object properties because they are reserved
|
||||
* by the runtime.
|
||||
*/
|
||||
const reservedMessageProperties = new Set([
|
||||
// names reserved by the runtime
|
||||
"getType",
|
||||
"clone",
|
||||
"equals",
|
||||
"fromBinary",
|
||||
"fromJson",
|
||||
"fromJsonString",
|
||||
"toBinary",
|
||||
"toJson",
|
||||
"toJsonString",
|
||||
// names reserved by the runtime for the future
|
||||
"toObject",
|
||||
]);
|
||||
const fallback = (name) => `${name}$`;
|
||||
/**
|
||||
* Will wrap names that are Object prototype properties or names reserved
|
||||
* for `Message`s.
|
||||
*/
|
||||
const safeMessageProperty = (name) => {
|
||||
if (reservedMessageProperties.has(name)) {
|
||||
return fallback(name);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
/**
|
||||
* Names that cannot be used for object properties because they are reserved
|
||||
* by built-in JavaScript properties.
|
||||
*/
|
||||
const safeObjectProperty = (name) => {
|
||||
if (reservedObjectProperties.has(name)) {
|
||||
return fallback(name);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
exports.safeObjectProperty = safeObjectProperty;
|
||||
/**
|
||||
* Names that can be used for identifiers or class properties
|
||||
*/
|
||||
const safeIdentifier = (name) => {
|
||||
if (reservedIdentifiers.has(name)) {
|
||||
return fallback(name);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
exports.safeIdentifier = safeIdentifier;
|
||||
Reference in New Issue
Block a user