279 lines
12 KiB
JavaScript
279 lines
12 KiB
JavaScript
import { parseDestructuring, parseFrom, parseIdentifier, parseWith } from './partParsers.js';
|
|
import { addError, getPosition, stripComments } from './utils.js';
|
|
/**
|
|
* Adds error of parsing `export` statement with declaration.
|
|
*/
|
|
export const onDeclarationExportError = (importsExports, _source, { start, end }) => addError(importsExports, 'Cannot find end of export with declaration', start, end);
|
|
/**
|
|
* Parses `export` statement with declaration.
|
|
*/
|
|
export const onDeclarationExportParse = (importsExports, source, { start, end: unparsedStart, comments }, { start: unparsedEnd, end: exportEnd, match: endMatch }) => {
|
|
var end = exportEnd;
|
|
var isDeclare = false;
|
|
var isType = false;
|
|
var unparsed = stripComments(source, unparsedStart, unparsedEnd, comments).trim();
|
|
if (unparsed.startsWith('declare ')) {
|
|
isDeclare = true;
|
|
unparsed = unparsed.slice(8).trim();
|
|
}
|
|
if (unparsed.startsWith('type ')) {
|
|
isType = true;
|
|
unparsed = unparsed.slice(5).trim();
|
|
}
|
|
const modifiers = `${isDeclare ? 'declare ' : ''}${isType ? 'type ' : ''}`;
|
|
if (unparsed[0] === '*') {
|
|
if (isDeclare) {
|
|
return addError(importsExports, `Cannot declare star export (\`export ${modifiers}* ... from ...\`)`, start, end);
|
|
}
|
|
let namespace;
|
|
if (unparsed.startsWith('* as ')) {
|
|
unparsed = unparsed.slice(5).trim();
|
|
const spaceIndex = unparsed.indexOf(' ');
|
|
if (spaceIndex === -1) {
|
|
return addError(importsExports, `Cannot find namespace of \`export ${modifiers}* as ... from ...\` statement`, start, end);
|
|
}
|
|
namespace = unparsed.slice(0, spaceIndex);
|
|
unparsed = unparsed.slice(spaceIndex + 1);
|
|
}
|
|
if (unparsed[unparsed.length - 1] === ';') {
|
|
unparsed = unparsed.slice(0, -1).trim();
|
|
}
|
|
const { groups } = endMatch;
|
|
let quoteCharacter;
|
|
if (groups.with === undefined) {
|
|
quoteCharacter = unparsed[unparsed.length - 1];
|
|
unparsed = unparsed.slice(0, -1);
|
|
}
|
|
else {
|
|
quoteCharacter = groups.with[0];
|
|
}
|
|
const reexportKind = `${namespace === undefined ? 'star' : 'namespace'} reexport`;
|
|
if (quoteCharacter !== "'" && quoteCharacter !== '"') {
|
|
return addError(importsExports, `Cannot find end of \`from\` string literal of ${reexportKind}`, start, end);
|
|
}
|
|
const { from, index } = parseFrom(quoteCharacter, unparsed);
|
|
if (index === -1) {
|
|
return addError(importsExports, `Cannot find start of \`from\` string literal of ${reexportKind}`, start, end);
|
|
}
|
|
let withAttributes;
|
|
if (groups.with !== undefined) {
|
|
if (isType) {
|
|
return addError(importsExports, `Cannot use import attributes (\`with {...}\`) in \`export ${modifiers}\` statement for ${reexportKind} from \`${from}\``, start, end);
|
|
}
|
|
const attributes = parseWith(exportEnd, source);
|
|
if (attributes === undefined) {
|
|
return addError(importsExports, `Cannot find end of import attributes (\`with {...}\`) for ${reexportKind} from \`${from}\``, start, end);
|
|
}
|
|
end = attributes.endIndex;
|
|
withAttributes = attributes.with;
|
|
if (withAttributes === undefined) {
|
|
return addError(importsExports, `Cannot parse import attributes (\`with {...}\`) for ${reexportKind} from \`${from}\``, start, end);
|
|
}
|
|
}
|
|
const position = getPosition(importsExports, start, end);
|
|
const parsedReexport = withAttributes === undefined ? position : { ...position, with: withAttributes };
|
|
let key = 'starReexports';
|
|
if (namespace !== undefined) {
|
|
parsedReexport.namespace = namespace;
|
|
key = 'namespaceReexports';
|
|
}
|
|
if (isType) {
|
|
key = key === 'starReexports' ? 'typeStarReexports' : 'typeNamespaceReexports';
|
|
}
|
|
let reexports = importsExports[key];
|
|
reexports !== null && reexports !== void 0 ? reexports : (reexports = importsExports[key] = { __proto__: null });
|
|
let reexportsList = reexports[from];
|
|
if (reexportsList === undefined) {
|
|
reexports[from] = [parsedReexport];
|
|
}
|
|
else {
|
|
reexportsList.push(parsedReexport);
|
|
}
|
|
return end;
|
|
}
|
|
const identifierIndex = parseIdentifier(unparsed);
|
|
if (identifierIndex === 0) {
|
|
return addError(importsExports, `Cannot parse declaration identifier of \`export ${modifiers}...\` statement`, start, end);
|
|
}
|
|
const identifier = unparsed.slice(0, identifierIndex);
|
|
if (isType) {
|
|
let { typeExports } = importsExports;
|
|
if (typeExports === undefined) {
|
|
importsExports.typeExports = typeExports = { __proto__: null };
|
|
}
|
|
else if (identifier in typeExports) {
|
|
return addError(importsExports, `Duplicate exported type \`${identifier}\``, start, end);
|
|
}
|
|
typeExports[identifier] = getPosition(importsExports, start, end);
|
|
if (isDeclare) {
|
|
typeExports[identifier].isDeclare = true;
|
|
}
|
|
return;
|
|
}
|
|
if (identifier === 'default') {
|
|
if (isDeclare) {
|
|
return addError(importsExports, `Cannot export default with declare (\`export ${modifiers}default ...\`)`, start, end);
|
|
}
|
|
if (importsExports.defaultExport !== undefined) {
|
|
return addError(importsExports, 'Duplicate default export', start, end);
|
|
}
|
|
importsExports.defaultExport = getPosition(importsExports, start, end);
|
|
return;
|
|
}
|
|
unparsed = unparsed.slice(identifierIndex).trim();
|
|
if (identifier === 'interface') {
|
|
const nameIndex = parseIdentifier(unparsed);
|
|
if (nameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse interface identifier of \`export ${modifiers}interface ...\` statement`, start, end);
|
|
}
|
|
const name = unparsed.slice(0, nameIndex);
|
|
let { interfaceExports } = importsExports;
|
|
interfaceExports !== null && interfaceExports !== void 0 ? interfaceExports : (interfaceExports = importsExports.interfaceExports = { __proto__: null });
|
|
const interfaceExport = getPosition(importsExports, start, end);
|
|
if (isDeclare) {
|
|
interfaceExport.isDeclare = true;
|
|
}
|
|
let exportsList = interfaceExports[name];
|
|
if (exportsList === undefined) {
|
|
interfaceExports[name] = [interfaceExport];
|
|
}
|
|
else {
|
|
exportsList.push(interfaceExport);
|
|
}
|
|
return;
|
|
}
|
|
if (identifier === 'namespace') {
|
|
const nameIndex = parseIdentifier(unparsed);
|
|
if (nameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse namespace identifier of \`export ${modifiers}namespace ...\` statement`, start, end);
|
|
}
|
|
const name = unparsed.slice(0, nameIndex);
|
|
let { namespaceExports } = importsExports;
|
|
namespaceExports !== null && namespaceExports !== void 0 ? namespaceExports : (namespaceExports = importsExports.namespaceExports = { __proto__: null });
|
|
const namespaceExport = getPosition(importsExports, start, end);
|
|
if (isDeclare) {
|
|
namespaceExport.isDeclare = true;
|
|
}
|
|
let exportsList = namespaceExports[name];
|
|
if (exportsList === undefined) {
|
|
namespaceExports[name] = [namespaceExport];
|
|
}
|
|
else {
|
|
exportsList.push(namespaceExport);
|
|
}
|
|
return;
|
|
}
|
|
var isAsync = false;
|
|
var kind;
|
|
const names = [];
|
|
switch (identifier) {
|
|
case 'const':
|
|
case 'class':
|
|
case 'enum':
|
|
case 'let':
|
|
case 'var':
|
|
if ((identifier === 'const' || identifier === 'let' || identifier === 'var') &&
|
|
(unparsed[0] === '{' || unparsed[0] === '[')) {
|
|
const destructuring = parseDestructuring(unparsed + source.slice(end));
|
|
if (destructuring === undefined) {
|
|
return addError(importsExports, `Cannot parse destructuring names in \`export ${modifiers}${identifier} ...\` statement`, start, end);
|
|
}
|
|
const endDiff = destructuring.endIndex - unparsed.length;
|
|
if (endDiff > 0) {
|
|
end += endDiff;
|
|
}
|
|
names.push(...destructuring.names);
|
|
kind = `destructuring ${identifier}`;
|
|
if (isDeclare) {
|
|
kind = `declare ${kind}`;
|
|
}
|
|
break;
|
|
}
|
|
const nameIndex = parseIdentifier(unparsed);
|
|
if (nameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse \`${identifier}\` identifier of \`export ${modifiers}${identifier} ...\` statement`, start, end);
|
|
}
|
|
kind = identifier;
|
|
if (isDeclare) {
|
|
kind = `declare ${kind}`;
|
|
}
|
|
names[0] = unparsed.slice(0, nameIndex);
|
|
if (identifier === 'const' && names[0] === 'enum') {
|
|
unparsed = unparsed.slice(4).trim();
|
|
const constEnumNameIndex = parseIdentifier(unparsed);
|
|
if (constEnumNameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse identifier of \`export ${modifiers}const enum ...\` statement`, start, end);
|
|
}
|
|
kind = 'const enum';
|
|
if (isDeclare) {
|
|
kind = `declare ${kind}`;
|
|
}
|
|
names[0] = unparsed.slice(0, constEnumNameIndex);
|
|
}
|
|
break;
|
|
case 'abstract':
|
|
if (!unparsed.startsWith('class ')) {
|
|
return addError(importsExports, `Cannot parse declaration of abstract class of \`export ${modifiers}abstract ...\` statement`, start, end);
|
|
}
|
|
unparsed = unparsed.slice(5).trim();
|
|
const abstractClassNameIndex = parseIdentifier(unparsed);
|
|
if (abstractClassNameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse \`${identifier}\` identifier of \`export ${modifiers}abstract class ${identifier} ...\` statement`, start, end);
|
|
}
|
|
kind = 'abstract class';
|
|
if (isDeclare) {
|
|
kind = `declare ${kind}`;
|
|
}
|
|
names[0] = unparsed.slice(0, abstractClassNameIndex);
|
|
break;
|
|
// @ts-expect-error
|
|
case 'async':
|
|
if (isDeclare) {
|
|
return addError(importsExports, `Cannot export async function with declare (\`export ${modifiers}async ...\`)`, start, end);
|
|
}
|
|
if (unparsed.startsWith('function') === false) {
|
|
return addError(importsExports, 'Cannot parse async function in `export async ...` statement', start, end);
|
|
}
|
|
isAsync = true;
|
|
unparsed = unparsed.slice(8).trim();
|
|
case 'function':
|
|
if (unparsed[0] === '*') {
|
|
if (isDeclare) {
|
|
return addError(importsExports, `Cannot export generator function with declare (\`export ${modifiers}function* ...\`)`, start, end);
|
|
}
|
|
unparsed = unparsed.slice(1).trim();
|
|
kind = 'function*';
|
|
}
|
|
else {
|
|
kind = 'function';
|
|
}
|
|
if (isAsync) {
|
|
kind = `async ${kind}`;
|
|
}
|
|
else if (isDeclare) {
|
|
kind = 'declare function';
|
|
}
|
|
const functionNameIndex = parseIdentifier(unparsed);
|
|
if (functionNameIndex === 0) {
|
|
return addError(importsExports, `Cannot parse \`${kind}\` identifier of \`export ${modifiers}${kind} ...\` statement`, start, end);
|
|
}
|
|
names[0] = unparsed.slice(0, functionNameIndex);
|
|
break;
|
|
default:
|
|
return addError(importsExports, `Cannot parse \`export ${modifiers}${identifier} ...\` statement`, start, end);
|
|
}
|
|
var { declarationExports } = importsExports;
|
|
declarationExports !== null && declarationExports !== void 0 ? declarationExports : (declarationExports = importsExports.declarationExports = {
|
|
__proto__: null,
|
|
});
|
|
for (const name of names) {
|
|
if (name in declarationExports) {
|
|
return addError(importsExports, `Duplicate exported declaration \`${kind} ${name}\``, start, end);
|
|
}
|
|
declarationExports[name] = {
|
|
...getPosition(importsExports, start, end),
|
|
kind: kind,
|
|
};
|
|
}
|
|
return end;
|
|
};
|