This commit is contained in:
Dirk Baeumer 2021-07-13 21:55:57 +02:00
Родитель fd6a872b17
Коммит c58c1b579e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: DD95715335E91385
31 изменённых файлов: 400 добавлений и 101 удалений

Просмотреть файл

@ -5,12 +5,6 @@
"author": "Microsoft Corporation",
"license": "MIT",
"private": true,
"dependencies": {
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/uuid": "^8.3.0"
},
"scripts": {
"compile": "node ../../bin/tsc -b ./tsconfig.json"
}

Просмотреть файл

@ -1,14 +0,0 @@
{
"name": "dart-code",
"repository": "https://github.com/Dart-Code/Dart-Code.git",
"init": [
{ "command": "npm", "args": ["install"] }
],
"tests": [
{
"config": {
"project": "./tsconfig.json"
}
}
]
}

Просмотреть файл

@ -1,25 +0,0 @@
{
"name": "lodash",
"repository": "https://github.com/lodash/lodash.git",
"init": [
{ "command": "npm", "args": ["install"] }
],
"tests": [
{
"config": {
"project": {
"compilerOptions": {
"rootDir": "./"
},
"include": [
"*.js",
"test/*.js"
]
},
"out": "lodash.lsif",
"package": "./package.json",
"source": "./package.json"
}
}
]
}

Просмотреть файл

@ -1,14 +0,0 @@
{
"name": "mobx",
"repository": "https://github.com/mobxjs/mobx.git",
"init": [
{ "command": "yarn", "args": ["install"] }
],
"tests": [
{
"config": {
"project": "./tsconfig.json"
}
}
]
}

Просмотреть файл

@ -1,14 +0,0 @@
{
"name": "sourcegraph",
"repository": "https://github.com/sourcegraph/sourcegraph.git",
"init": [
{ "command": "yarn", "args": ["install", "--ignore-engines"] }
],
"tests": [
{
"config": {
"project": "./tsconfig.all.json"
}
}
]
}

203
build/bin/testConfigs.js Normal file
Просмотреть файл

@ -0,0 +1,203 @@
#!/usr/bin/env node
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
"use strict";
//@ts-check
const path = require('path');
const util = require('util');
const os = require('os');
const cp = require('child_process');
const _fs = require('fs');
const fs = _fs.promises;
const exists = util.promisify(_fs.exists);
const uuid = require('uuid');
const ROOT = path.join(__dirname, '..', '..');
/**
* @param {string} command
* @param {ReadonlyArray<string>} args
* @param {string | undefined} cwd
* @returns {Promise<number | undefined>}
*/
async function runCommand(command, args, cwd) {
return new Promise((resolve, reject) => {
const process = cp.spawn(command, args, {
cwd,
stdio: 'inherit',
shell: true
});
let resolved = false;
const handleEnd = (code, signal) => {
if (resolved) {
return;
}
resolved = true;
if (signal) {
reject(1);
}
if (code === null || code === 0) {
resolve(undefined);
} else {
reject(code);
}
}
process.on('close', handleEnd);
process.on('exit', handleEnd);
process.on('error', (error) => {
console.error(error);
reject(1);
});
})
}
/**
* @param {string} file
* @returns { { command: string; args: string[]; }[] }
*/
async function readInitFile(initFile) {
return JSON.parse(await fs.readFile(initFile, { encoding: 'utf8' }));
}
/**
*
* @param {string} cwd
* @param {string} configFilePath
* @returns {Promise<string>}
*/
async function runLsifTsc(cwd, configFilePath) {
const out = `${uuid.v4()}.lsif`;
const args = [path.join(ROOT, 'tsc', 'lib', 'main.js')];
args.push('--config', configFilePath);
args.push('--out', path.join(cwd, out));
await runCommand('node', args, cwd);
return out;
}
/**
*
* @param {string} cwd
* @param {string} outFile
* @return {Promise<void>}
*/
async function runValidate(cwd, outFile) {
const args = [path.join(ROOT, 'tooling', 'lib', 'main.js'),
'--in', `${outFile}`
];
await runCommand('node', args, cwd);
}
/**
*
* @param {string} root
* @param {string} hub
* @param {string} org
* @param {string} repository
*/
async function checkRepository(root, hub, org, repository) {
if (hub === 'github.com') {
const url = `https://github.com/${org}/${repository}`;
process.stdout.write(`====================== Checking repository ${url} ===========================\n\n`);
const tmpdir = os.tmpdir();
const directory = path.join(tmpdir, repository);
if (await exists(directory)) {
await fs.rmdir(directory, { recursive: true });
}
await runCommand('git', ['clone', '--depth 1', url, directory]);
const initFile = path.join(root, hub, org, repository, 'init.json');
if (await exists(initFile)) {
const content = await readInitFile(initFile);
for (const command of content) {
await runCommand(command.command, command.args ?? [], directory);
}
}
let configFile = path.join(root, hub, org, repository, '.lsifrc.json');
if (!await exists(configFile)) {
configFile = path.join(root, hub, org, repository, '.lsifrc-test.json');
}
if (await exists(configFile)) {
await fs.writeFile(path.join(directory, '.lsifrc.json'), await fs.readFile(configFile), { encoding: 'utf8' });
process.stdout.write(`Run LSIF tool\n`);
const out = await runLsifTsc(directory, '.lsifrc.json');
process.stdout.write(`Run Validation tool\n`);
await runValidate(directory, out);
await fs.rmdir(directory, { recursive: true });
}
}
}
/**
* @param {string} configs
* @param {string} hub
* @param {string} org
* @param {string} repository
*/
async function main(configs, hub, org, repository) {
if (configs === undefined) {
configs = './configs';
}
if (!path.isAbsolute(configs)) {
configs = path.join(process.cwd(), configs);
}
const testStats = { passed: [], failed: [] };
if (hub !== undefined && repository !== undefined) {
try {
await checkRepository(configs, hub, org, repository);
testStats.passed.push(`${hub}/${org}/${repository}`);
} catch (error) {
testStats.failed.push(`${hub}/${org}/${repository}`);
}
} else {
const hubs = await fs.readdir(configs);
for (const hub of hubs) {
if (hub === '.' || hub === '..') {
continue;
}
const organizations = await fs.readdir(path.join(configs, hub));
for (const org of organizations) {
if (org === '.' || org === '..') {
continue;
}
const repositories = await fs.readdir(path.join(configs, hub, org));
for (const repository of repositories) {
if (repository === '.' || repository === '..') {
continue;
}
try {
await checkRepository(configs, hub, org, repository);
testStats.passed.push(`${hub}/${org}/${repository}`);
} catch {
testStats.failed.push(`${hub}/${org}/${repository}`);
}
}
}
}
}
process.stdout.write(`\n\nTest summary:\n`);
process.stdout.write(`\tPassed tests: ${testStats.passed.length}\n`);
process.stdout.write(`\tFailed tests: ${testStats.failed.length}\n`);
if (testStats.failed.length > 0) {
for (let failed of testStats.failed) {
process.stdout.write(`\t\t${failed}\n`);
}
}
return testStats.failed.length > 0 ? 1 : undefined;
}
main(process.argv[2], process.argv[3], process.argv[4], process.argv[5]).then((error) => {
if (error !== undefined) {
process.exitCode = error;
}
}, (_error) => {
process.exitCode = 1;
});

Просмотреть файл

@ -0,0 +1,6 @@
{
"project": "./tsconfig.json",
"out": "dart-code.lsif",
"package": "./package.json",
"source": "./package.json"
}

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -1,6 +1,6 @@
{
"project": {
"compilerOPtions": {
"compilerOptions": {
"rootDir": "./"
},
"include": [

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "yarn", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install", "--force"] }
]

Просмотреть файл

@ -0,0 +1,6 @@
{
"project": "./tsconfig.all.json",
"out": "sg.lsif",
"package": "./package.json",
"source": "./package.json"
}

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "yarn", "args": ["install", "--ignore-engines"] }
]

Просмотреть файл

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

Просмотреть файл

@ -0,0 +1,3 @@
[
{ "command": "npm", "args": ["install"] }
]

31
package-lock.json сгенерированный
Просмотреть файл

@ -11,6 +11,7 @@
"devDependencies": {
"@types/node": "^12.12.29",
"@types/shelljs": "^0.8.8",
"@types/uuid": "^8.3.1",
"@types/yargs": "^16.0.1",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
@ -18,7 +19,8 @@
"mocha": "^9.0.1",
"rimraf": "^3.0.2",
"shelljs": "^0.8.4",
"typescript": "^4.2.3"
"typescript": "^4.2.3",
"uuid": "^8.3.2"
}
},
"node_modules/@babel/code-frame": {
@ -202,6 +204,12 @@
"@types/node": "*"
}
},
"node_modules/@types/uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==",
"dev": true
},
"node_modules/@types/yargs": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.1.tgz",
@ -2177,6 +2185,15 @@
"punycode": "^2.1.0"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
@ -2512,6 +2529,12 @@
"@types/node": "*"
}
},
"@types/uuid": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==",
"dev": true
},
"@types/yargs": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.1.tgz",
@ -3941,6 +3964,12 @@
"punycode": "^2.1.0"
}
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true
},
"v8-compile-cache": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",

Просмотреть файл

@ -16,6 +16,7 @@
"devDependencies": {
"@types/node": "^12.12.29",
"@types/shelljs": "^0.8.8",
"@types/uuid": "^8.3.1",
"@types/yargs": "^16.0.1",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
@ -23,7 +24,8 @@
"mocha": "^9.0.1",
"rimraf": "^3.0.2",
"shelljs": "^0.8.4",
"typescript": "^4.2.3"
"typescript": "^4.2.3",
"uuid": "^8.3.2"
},
"scripts": {
"postinstall": "node ./build/bin/all.js install && npm run symlink && cd samples/typescript && npm install && cd ../javascript && npm install && cd ../..",

Просмотреть файл

@ -11,7 +11,9 @@ import { ValidateCommand } from './validate';
import { Options, builder } from './args';
class ConsoleDiagnosticReporter implements DiagnosticReporter {
hasError: boolean = false;
error(element: Edge | Vertex, message?: string): void {
this.hasError = true;
if (message === undefined) {
if (element.type === ElementTypes.edge) {
console.log(`Malformed edge ${JSON.stringify(element, undefined, 0)}:`);
@ -42,7 +44,11 @@ export async function run(options: Options): Promise<void> {
if (options.in !== undefined && fs.existsSync(options.in)) {
input = fs.createReadStream(options.in, { encoding: 'utf8'});
}
await new ValidateCommand(input, {}, new ConsoleDiagnosticReporter()).run();
const reporter = new ConsoleDiagnosticReporter();
await new ValidateCommand(input, {}, reporter).run();
if (reporter.hasError) {
process.exitCode = 1;
}
}
export async function main(): Promise<void> {

Просмотреть файл

@ -95,4 +95,77 @@ suite('JavaScript Tests', () => {
}
});
test('exports.paramsHaveValue', async () => {
const emitter = await lsif('/@test', new Map([
[
'/@test/a.js',
[
'function paramsHaveValue() {',
'}',
'exports.paramsHaveValue = paramsHaveValue;'
].join(os.EOL)
],
[
'/@test/b.js',
[
'const a = require("./a");',
'a.paramsHaveValue();'
].join(os.EOL)
]
]), compilerOptions);
const validate: Element[] = [
JSON.parse('{"id":14,"type":"vertex","label":"resultSet"}'),
JSON.parse('{"id":15,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"Y8eS7TVHlwRY6NxeVit0vw==","unique":"document","kind":"local"}'),
JSON.parse('{"id":16,"type":"edge","label":"moniker","outV":14,"inV":15}'),
JSON.parse('{"id":21,"type":"vertex","label":"resultSet"}'),
JSON.parse('{"id":22,"type":"edge","label":"next","outV":21,"inV":14}'),
JSON.parse('{"id":23,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"a:paramsHaveValue","unique":"workspace","kind":"export"}'),
JSON.parse('{"id":24,"type":"edge","label":"moniker","outV":21,"inV":23}'),
JSON.parse('{"id":25,"type":"vertex","label":"range","start":{"line":2,"character":8},"end":{"line":2,"character":23},"tag":{"type":"definition","text":"paramsHaveValue","kind":7,"fullRange":{"start":{"line":2,"character":0},"end":{"line":2,"character":23}}}}'),
JSON.parse('{"id":26,"type":"edge","label":"next","outV":25,"inV":21}')
];
for (const elem of validate) {
assertElement(emitter.elements.get(elem.id), elem);
}
});
test('exports.paramsHaveValue with indirect exports', async () => {
const emitter = await lsif('/@test', new Map([
[
'/@test/a.js',
[
'function paramsHaveValue() {',
' return { value: 10 };',
'}',
'exports.paramsHaveValue = paramsHaveValue;'
].join(os.EOL)
],
[
'/@test/b.js',
[
'const a = require("./a");',
'a.paramsHaveValue().value;'
].join(os.EOL)
]
]), compilerOptions);
const validate: Element[] = [
JSON.parse('{"id":14,"type":"vertex","label":"resultSet"}'),
JSON.parse('{"id":15,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"jg4X3igUOm47P4m1B9f93A==","unique":"document","kind":"local"}'),
JSON.parse('{"id":16,"type":"edge","label":"moniker","outV":14,"inV":15}'),
JSON.parse('{"id":21,"type":"vertex","label":"resultSet"}'),
JSON.parse('{"id":22,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"GmrY/zPTHrjN6AQD23azuA==","unique":"document","kind":"local"}'),
JSON.parse('{"id":23,"type":"edge","label":"moniker","outV":21,"inV":22}'),
JSON.parse('{"id":24,"type":"vertex","label":"range","start":{"line":1,"character":13},"end":{"line":1,"character":18},"tag":{"type":"definition","text":"value","kind":7,"fullRange":{"start":{"line":1,"character":13},"end":{"line":1,"character":22}}}}'),
JSON.parse('{"id":25,"type":"edge","label":"next","outV":24,"inV":21}'),
JSON.parse('{"id":28,"type":"vertex","label":"resultSet"}'),
JSON.parse('{"id":29,"type":"edge","label":"next","outV":28,"inV":14}'),
JSON.parse('{"id":30,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"a:paramsHaveValue","unique":"workspace","kind":"export"}'),
JSON.parse('{"id":31,"type":"edge","label":"moniker","outV":28,"inV":30}'),
JSON.parse('{"id":40,"type":"vertex","label":"moniker","scheme":"tsc","identifier":"a:paramsHaveValue.__rt.value","unique":"workspace","kind":"export"}'),
JSON.parse('{"id":41,"type":"edge","label":"attach","outV":40,"inV":22}')
];
for (const elem of validate) {
assertElement(emitter.elements.get(elem.id), elem);
}
});
});

Просмотреть файл

@ -530,7 +530,7 @@ abstract class SymbolData extends LSIFData<SymbolDataContext> {
return;
}
if (this.visibility === SymbolDataVisibility.internal) {
throw new Error(`Can't upgrade symbol data visibility from ${this.visibility} to ${value}`);
throw new Error(`Can't upgrade symbol data visibility for ${this.symbolId} from ${this.visibility} to ${value}`);
}
this.visibility = value;
return;
@ -3769,31 +3769,33 @@ class Visitor {
return;
}
const left = node.expression.left;
if (!ts.isIdentifier(left.expression) || left.expression.escapedText !== 'module' || left.name.escapedText !== 'exports') {
return;
}
// We do have module.exports =
const symbol = this.tsProject.getSymbolAtLocation(node.expression.left);
if (symbol === undefined) {
return;
const isModuleExport = ts.isIdentifier(left.expression) && left.expression.escapedText === 'module' && left.name.escapedText === 'exports';
const isExport = ts.isIdentifier(left.expression) && left.expression.escapedText === 'exports' && ts.isIdentifier(left.name);
if (isModuleExport || isExport) {
// First upgrade the aliased symbol even if we can't generate a moniker for it
const aliasedSymbol = this.tsProject.getSymbolAtLocation(node.expression.right);
if (aliasedSymbol === undefined) {
return;
}
const aliasedSymbolData = this.dataManager.getOrCreateSymbolData(aliasedSymbol);
if (aliasedSymbolData === undefined) {
return;
}
aliasedSymbolData.changeVisibility(SymbolDataVisibility.indirectExported);
const symbol = this.tsProject.getSymbolAtLocation(left);
if (symbol === undefined) {
return;
}
this.dataManager.getOrCreateSymbolData(symbol);
const monikerPath = this.currentDocumentData.monikerPath;
if (monikerPath === undefined) {
return;
}
this.tsProject.exportSymbol(aliasedSymbol, monikerPath, this.tsProject.getExportSymbolName(symbol), this.currentSourceFile);
}
// Make sure we have a symbol data;
this.dataManager.getOrCreateSymbolData(symbol);
const monikerPath = this.currentDocumentData.monikerPath;
if (monikerPath === undefined) {
return;
}
const aliasedSymbol = this.tsProject.getSymbolAtLocation(node.expression.right);
if (aliasedSymbol === undefined) {
return;
}
const aliasedSymbolData = this.dataManager.getOrCreateSymbolData(aliasedSymbol);
if (aliasedSymbolData === undefined) {
return;
}
aliasedSymbolData.changeVisibility(SymbolDataVisibility.indirectExported);
this.tsProject.exportSymbol(aliasedSymbol, monikerPath, this.tsProject.getExportSymbolName(symbol), this.currentSourceFile);
}
private visitArrayType(_node: ts.ArrayTypeNode): boolean {