[wip] Fix CI (#202)

* Yarn format

* Fix changeset --since

* Fix Windows tests
This commit is contained in:
Drew Powers 2021-05-12 12:06:16 -06:00 committed by GitHub
parent 88529b679a
commit 3ef1b01e14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 196 additions and 224 deletions

View file

@ -9,31 +9,29 @@ on:
- 'examples/**' - 'examples/**'
- 'www/**' - 'www/**'
branches: branches:
- main - main
jobs: jobs:
release: release:
name: Changelog name: Changelog
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Check out branch
uses: actions/checkout@master uses: actions/checkout@v2
with: with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- name: Setup Node.js 14.x - name: Set up Node.js 14.x
uses: actions/setup-node@master uses: actions/setup-node@v2
with: with:
node-version: 14.x node-version: 14.x
- name: Install Dependencies - name: Install dependencies
run: yarn --frozen-lockfile run: yarn --frozen-lockfile --ignore-engines
env: env:
CI: true CI: true
- name: Create Release Pull Request - name: Create release PR
uses: changesets/action@master uses: changesets/action@master
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,26 +0,0 @@
name: Changeset
on:
pull_request:
branches:
- main
jobs:
release:
name: Ensure changeset
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@master
- name: Setup Node.js 14.x
uses: actions/setup-node@master
with:
node-version: 14.x
- name: Install Dependencies
run: yarn --frozen-lockfile
env:
CI: true
- run: yarn changeset status --since=main

View file

@ -15,10 +15,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
- uses: actions/setup-node@v1 - uses: actions/setup-node@v2
with: with:
node-version: ${{ env.node_version }} node-version: ${{ env.node_version }}
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile --ignore-engines
env: env:
CI: true CI: true
- run: yarn format - run: yarn format

View file

@ -9,7 +9,7 @@ on:
- main - main
jobs: jobs:
skip_test: skip_run:
continue-on-error: true continue-on-error: true
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
@ -23,21 +23,46 @@ jobs:
skip_after_successful_duplicate: 'true' skip_after_successful_duplicate: 'true'
paths_ignore: '["**/README.md", "**/docs/**"]' paths_ignore: '["**/README.md", "**/docs/**"]'
do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]'
changeset:
needs: skip_run # allow skip_run to cancel this job if its not needed
if: ${{ needs.skip_run.outputs.should_skip != 'true' }}
name: Ensure changeset
runs-on: ubuntu-latest
steps:
- name: Check out PR branch
uses: actions/checkout@v2
- name: Check out main branch
uses: actions/checkout@v2
with:
ref: main
- name: Set up Node.js 14.x
uses: actions/setup-node@v2
with:
node-version: 14.x
- name: Install dependencies
run: yarn --frozen-lockfile --ignore-engines
env:
CI: true
- run: yarn changeset status --since=main
test: test:
needs: skip_test # allow skip_test to cancel this job if its not needed needs: skip_run # allow skip_run to cancel this job if its not needed
if: ${{ needs.skip_test.outputs.should_skip != 'true' }} if: ${{ needs.skip_run.outputs.should_skip != 'true' }}
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest]
node-version: [14.x, 15.x] node-version: [14.x, 16.x]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- run: yarn --frozen-lockfile - run: yarn --frozen-lockfile --ignore-engines
env: env:
CI: true CI: true
- run: yarn build - run: yarn build

View file

@ -29,6 +29,9 @@
"npm": "7.11.2", "npm": "7.11.2",
"yarn": "1.22.10" "yarn": "1.22.10"
}, },
"dependencies": {
"@changesets/cli": "^2.16.0"
},
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.18.0", "@typescript-eslint/parser": "^4.18.0",
@ -46,8 +49,5 @@
"tiny-glob": "^0.2.8", "tiny-glob": "^0.2.8",
"typescript": "^4.2.4", "typescript": "^4.2.4",
"uvu": "^0.5.1" "uvu": "^0.5.1"
},
"dependencies": {
"@changesets/cli": "^2.16.0"
} }
} }

View file

@ -1,6 +1,7 @@
# astro-prism # astro-prism
## 0.0.2 ## 0.0.2
### Patch Changes ### Patch Changes
- d924fcb: Fix issue with Prism component missing dependency - d924fcb: Fix issue with Prism component missing dependency

View file

@ -42,14 +42,11 @@ function globSearch(spec: string, { filename }: { filename: string }): string[]
} }
const cwd = path.join(path.dirname(filename), globDir.replace(/\//g, path.sep)); // this must match OS (could be '/' or '\') const cwd = path.join(path.dirname(filename), globDir.replace(/\//g, path.sep)); // this must match OS (could be '/' or '\')
let found = crawler let found = crawler.glob(glob).crawlWithOptions(cwd, { includeBasePath: true }).sync() as PathsOutput;
.glob(glob)
.crawlWithOptions(cwd, { includeBasePath: true })
.sync() as PathsOutput;
if (!found.length) { if (!found.length) {
throw new Error(`No files matched "${spec}" from ${filename}`); throw new Error(`No files matched "${spec}" from ${filename}`);
} }
return found.map(importPath => { return found.map((importPath) => {
if (importPath.startsWith('http') || importPath.startsWith('.')) return importPath; if (importPath.startsWith('http') || importPath.startsWith('.')) return importPath;
return './' + path.posix.join(globDir, path.posix.relative(slash(cwd), importPath)); return './' + path.posix.join(globDir, path.posix.relative(slash(cwd), importPath));
}); });

View file

@ -9,8 +9,8 @@ setup(Basics, './fixtures/astro-basic');
Basics('Can load page', async ({ runtime }) => { Basics('Can load page', async ({ runtime }) => {
const result = await runtime.load('/'); const result = await runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('h1').text(), 'Hello world!'); assert.equal($('h1').text(), 'Hello world!');

View file

@ -10,8 +10,8 @@ setupBuild(ComponentChildren, './fixtures/astro-children');
ComponentChildren('Passes string children to framework components', async ({ runtime }) => { ComponentChildren('Passes string children to framework components', async ({ runtime }) => {
let result = await runtime.load('/strings'); let result = await runtime.load('/strings');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
const $preact = $('#preact'); const $preact = $('#preact');
@ -26,8 +26,8 @@ ComponentChildren('Passes string children to framework components', async ({ run
ComponentChildren('Passes markup children to framework components', async ({ runtime }) => { ComponentChildren('Passes markup children to framework components', async ({ runtime }) => {
let result = await runtime.load('/markup'); let result = await runtime.load('/markup');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
const $preact = $('#preact > h1'); const $preact = $('#preact > h1');
@ -42,8 +42,8 @@ ComponentChildren('Passes markup children to framework components', async ({ run
ComponentChildren('Passes multiple children to framework components', async ({ runtime }) => { ComponentChildren('Passes multiple children to framework components', async ({ runtime }) => {
let result = await runtime.load('/multiple'); let result = await runtime.load('/multiple');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
const $preact = $('#preact'); const $preact = $('#preact');

View file

@ -9,6 +9,7 @@ setup(Collections, './fixtures/astro-collection');
Collections('generates list & sorts successfully', async ({ runtime }) => { Collections('generates list & sorts successfully', async ({ runtime }) => {
const result = await runtime.load('/posts'); const result = await runtime.load('/posts');
if (result.error) throw new Error(result.error);
const $ = doc(result.contents); const $ = doc(result.contents);
const urls = [ const urls = [
...$('#posts a').map(function () { ...$('#posts a').map(function () {
@ -20,6 +21,7 @@ Collections('generates list & sorts successfully', async ({ runtime }) => {
Collections('generates pagination successfully', async ({ runtime }) => { Collections('generates pagination successfully', async ({ runtime }) => {
const result = await runtime.load('/posts'); const result = await runtime.load('/posts');
if (result.error) throw new Error(result.error);
const $ = doc(result.contents); const $ = doc(result.contents);
const prev = $('#prev-page'); const prev = $('#prev-page');
const next = $('#next-page'); const next = $('#next-page');

View file

@ -10,9 +10,9 @@ setupBuild(CSSBundling, './fixtures/astro-css-bundling');
// note: the hashes should be deterministic, but updating the file contents will change hashes // note: the hashes should be deterministic, but updating the file contents will change hashes
// be careful not to test that the HTML simply contains CSS, because it always will! filename and quanity matter here (bundling). // be careful not to test that the HTML simply contains CSS, because it always will! filename and quanity matter here (bundling).
const EXPECTED_CSS = { const EXPECTED_CSS = {
'/index.html': ['/_astro/common-ZVuUT3.css', '/_astro/index-Z2jH7pc.css'], '/index.html': ['/_astro/common-', '/_astro/index-'], // dont match hashes, which change based on content
'/one/index.html': ['/_astro/common-ZVuUT3.css', '/_astro/one/index-2qFtfN.css'], '/one/index.html': ['/_astro/common-', '/_astro/one/index-'],
'/two/index.html': ['/_astro/common-ZVuUT3.css', '/_astro/two/index-2jKE68.css'], '/two/index.html': ['/_astro/common-', '/_astro/two/index-'],
}; };
const UNEXPECTED_CSS = ['/_astro/components/nav.css', '../css/typography.css', '../css/colors.css', '../css/page-index.css', '../css/page-one.css', '../css/page-two.css']; const UNEXPECTED_CSS = ['/_astro/components/nav.css', '../css/typography.css', '../css/colors.css', '../css/page-index.css', '../css/page-one.css', '../css/page-two.css'];
@ -28,9 +28,9 @@ CSSBundling('Bundles CSS', async (context) => {
// test 1: assert new bundled CSS is present // test 1: assert new bundled CSS is present
for (const href of css) { for (const href of css) {
builtCSS.add(href); const link = $(`link[href^="${href}"]`);
const link = $(`link[href="${href}"]`);
assert.equal(link.length, 1); assert.equal(link.length, 1);
builtCSS.add(link.attr('href'));
} }
// test 2: assert old CSS was removed // test 2: assert old CSS was removed

View file

@ -34,8 +34,7 @@ DType('No errors creating a runtime', () => {
DType('Automatically prepends the standards mode doctype', async () => { DType('Automatically prepends the standards mode doctype', async () => {
const result = await runtime.load('/prepend'); const result = await runtime.load('/prepend');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const html = result.contents.toString('utf-8'); const html = result.contents.toString('utf-8');
assert.ok(html.startsWith('<!doctype html>'), 'Doctype always included'); assert.ok(html.startsWith('<!doctype html>'), 'Doctype always included');
@ -43,8 +42,7 @@ DType('Automatically prepends the standards mode doctype', async () => {
DType.skip('Preserves user provided doctype', async () => { DType.skip('Preserves user provided doctype', async () => {
const result = await runtime.load('/preserve'); const result = await runtime.load('/preserve');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const html = result.contents.toString('utf-8'); const html = result.contents.toString('utf-8');
assert.ok(html.startsWith('<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'), 'Doctype included was preserved'); assert.ok(html.startsWith('<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'), 'Doctype included was preserved');

View file

@ -9,8 +9,7 @@ setupBuild(DynamicComponents, './fixtures/astro-dynamic');
DynamicComponents('Loads client-only packages', async ({ runtime }) => { DynamicComponents('Loads client-only packages', async ({ runtime }) => {
let result = await runtime.load('/'); let result = await runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
// Grab the react-dom import // Grab the react-dom import
const exp = /import\("(.+?)"\)/g; const exp = /import\("(.+?)"\)/g;

View file

@ -9,8 +9,7 @@ setup(Expressions, './fixtures/astro-expr');
Expressions('Can load page', async ({ runtime }) => { Expressions('Can load page', async ({ runtime }) => {
const result = await runtime.load('/'); const result = await runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
@ -21,8 +20,7 @@ Expressions('Can load page', async ({ runtime }) => {
Expressions('Ignores characters inside of strings', async ({ runtime }) => { Expressions('Ignores characters inside of strings', async ({ runtime }) => {
const result = await runtime.load('/strings'); const result = await runtime.load('/strings');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
@ -33,7 +31,7 @@ Expressions('Ignores characters inside of strings', async ({ runtime }) => {
Expressions('Ignores characters inside of line comments', async ({ runtime }) => { Expressions('Ignores characters inside of line comments', async ({ runtime }) => {
const result = await runtime.load('/line-comments'); const result = await runtime.load('/line-comments');
assert.equal(result.statusCode, 200); if (result.error) throw new Error(result.error);
const $ = doc(result.contents); const $ = doc(result.contents);
@ -44,7 +42,7 @@ Expressions('Ignores characters inside of line comments', async ({ runtime }) =>
Expressions('Ignores characters inside of multiline comments', async ({ runtime }) => { Expressions('Ignores characters inside of multiline comments', async ({ runtime }) => {
const result = await runtime.load('/multiline-comments'); const result = await runtime.load('/multiline-comments');
assert.equal(result.statusCode, 200); if (result.error) throw new Error(result.error);
const $ = doc(result.contents); const $ = doc(result.contents);
@ -55,7 +53,7 @@ Expressions('Ignores characters inside of multiline comments', async ({ runtime
Expressions('Allows multiple JSX children in mustache', async ({ runtime }) => { Expressions('Allows multiple JSX children in mustache', async ({ runtime }) => {
const result = await runtime.load('/multiple-children'); const result = await runtime.load('/multiple-children');
assert.equal(result.statusCode, 200); if (result.error) throw new Error(result.error);
assert.ok(result.contents.includes('#f') && !result.contents.includes('#t')); assert.ok(result.contents.includes('#f') && !result.contents.includes('#t'));
}); });

View file

@ -9,8 +9,7 @@ setup(Fallback, './fixtures/astro-fallback');
Fallback('Shows static content', async (context) => { Fallback('Shows static content', async (context) => {
const result = await context.runtime.load('/'); const result = await context.runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('#fallback').text(), 'static'); assert.equal($('#fallback').text(), 'static');

View file

@ -9,8 +9,7 @@ setup(Global, './fixtures/astro-global');
Global('Astro.request.url', async (context) => { Global('Astro.request.url', async (context) => {
const result = await context.runtime.load('/'); const result = await context.runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('#pathname').text(), '/'); assert.equal($('#pathname').text(), '/');
@ -35,8 +34,7 @@ Global('Astro.request.canonicalURL', async (context) => {
Global('Astro.site', async (context) => { Global('Astro.site', async (context) => {
const result = await context.runtime.load('/'); const result = await context.runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('#site').attr('href'), 'https://mysite.dev'); assert.equal($('#site').attr('href'), 'https://mysite.dev');

View file

@ -43,8 +43,7 @@ Markdown('No errors creating a runtime', () => {
Markdown('Can load markdown pages with hmx', async () => { Markdown('Can load markdown pages with hmx', async () => {
const result = await runtime.load('/post'); const result = await runtime.load('/post');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.ok($('#first').length, 'There is a div added in markdown'); assert.ok($('#first').length, 'There is a div added in markdown');
@ -53,6 +52,7 @@ Markdown('Can load markdown pages with hmx', async () => {
Markdown('Can load more complex jsxy stuff', async () => { Markdown('Can load more complex jsxy stuff', async () => {
const result = await runtime.load('/complex'); const result = await runtime.load('/complex');
if (result.error) throw new Error(result.error);
const $ = doc(result.contents); const $ = doc(result.contents);
const $el = $('#test'); const $el = $('#test');

View file

@ -35,8 +35,7 @@ React('No error creating the runtime', () => {
React('Can load React', async () => { React('Can load React', async () => {
const result = await runtime.load('/'); const result = await runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('#react-h2').text(), 'Hello world!'); assert.equal($('#react-h2').text(), 'Hello world!');
@ -44,8 +43,7 @@ React('Can load React', async () => {
React('Can load Vue', async () => { React('Can load Vue', async () => {
const result = await runtime.load('/'); const result = await runtime.load('/');
if (result.error) throw new Error(result.error);
assert.equal(result.statusCode, 200);
const $ = doc(result.contents); const $ = doc(result.contents);
assert.equal($('#vue-h2').text(), 'Hasta la vista, baby'); assert.equal($('#vue-h2').text(), 'Hasta la vista, baby');

View file

@ -20,7 +20,10 @@ const defaultConfig = {
export default async function build(...args) { export default async function build(...args) {
const config = Object.assign({}, defaultConfig); const config = Object.assign({}, defaultConfig);
const isDev = args.slice(-1)[0] === 'IS_DEV'; const isDev = args.slice(-1)[0] === 'IS_DEV';
let entryPoints = [].concat(...(await Promise.all(args.map((pattern) => glob(pattern, { filesOnly: true, absolute: true }))))); const patterns = args
.filter((f) => !!f) // remove empty args
.map((f) => f.replace(/^'/, '').replace(/'$/, '')); // Needed for Windows: glob strings contain surrounding string chars??? remove these
let entryPoints = [].concat(...(await Promise.all(patterns.map((pattern) => glob(pattern, { filesOnly: true, absolute: true })))));
const { type = 'module', dependencies = {} } = await fs.readFile('./package.json').then((res) => JSON.parse(res.toString())); const { type = 'module', dependencies = {} } = await fs.readFile('./package.json').then((res) => JSON.parse(res.toString()));
const format = type === 'module' ? 'esm' : 'cjs'; const format = type === 'module' ? 'esm' : 'cjs';

View file

@ -3,4 +3,4 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const { startServer } = require('../dist/index'); const { startServer } = require('../dist/index');
startServer(); startServer();

View file

@ -71,7 +71,7 @@ export function startServer() {
connection.onDidCloseTextDocument((evt) => docManager.closeDocument(evt.textDocument.uri)); connection.onDidCloseTextDocument((evt) => docManager.closeDocument(evt.textDocument.uri));
connection.onDidChangeTextDocument((evt) => { connection.onDidChangeTextDocument((evt) => {
docManager.updateDocument(evt.textDocument.uri, evt.contentChanges) docManager.updateDocument(evt.textDocument.uri, evt.contentChanges);
}); });
connection.onDidChangeWatchedFiles((evt) => { connection.onDidChangeWatchedFiles((evt) => {

View file

@ -26,11 +26,12 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
const fragment = await tsDoc.getFragment(); const fragment = await tsDoc.getFragment();
const offset = document.offsetAt(position); const offset = document.offsetAt(position);
const entries = lang.getCompletionsAtPosition(fragment.filePath, offset, { const entries =
importModuleSpecifierPreference: 'relative', lang.getCompletionsAtPosition(fragment.filePath, offset, {
importModuleSpecifierEnding: 'auto', importModuleSpecifierPreference: 'relative',
quotePreference: 'single' importModuleSpecifierEnding: 'auto',
})?.entries || []; quotePreference: 'single',
})?.entries || [];
const completionItems = entries const completionItems = entries
.map((entry: ts.CompletionEntry) => this.toCompletionItem(fragment, entry, document.uri, position, new Set())) .map((entry: ts.CompletionEntry) => this.toCompletionItem(fragment, entry, document.uri, position, new Set()))
@ -49,7 +50,7 @@ export class CompletionsProviderImpl implements CompletionsProvider<CompletionEn
return completionItem; return completionItem;
} }
if(filePath.endsWith('.astro')) { if (filePath.endsWith('.astro')) {
filePath = filePath + '.ts'; filePath = filePath + '.ts';
} }

View file

@ -72,7 +72,7 @@ async function createLanguageService(tsconfigPath: string, workspaceRoot: string
let projectVersion = 0; let projectVersion = 0;
const snapshotManager = new SnapshotManager(project.fileNames, { exclude: ['node_modules', 'dist'], include: ['astro'] }, workspaceRoot || process.cwd()); const snapshotManager = new SnapshotManager(project.fileNames, { exclude: ['node_modules', 'dist'], include: ['astro'] }, workspaceRoot || process.cwd());
const astroModuleLoader = createAstroModuleLoader(getScriptSnapshot, {}); const astroModuleLoader = createAstroModuleLoader(getScriptSnapshot, {});
const host: ts.LanguageServiceHost = { const host: ts.LanguageServiceHost = {

View file

@ -1,50 +1,46 @@
import ts from 'typescript'; import ts from 'typescript';
import type { DocumentSnapshot } from './SnapshotManager'; import type { DocumentSnapshot } from './SnapshotManager';
import { import { isVirtualAstroFilePath, ensureRealAstroFilePath, getExtensionFromScriptKind } from './utils';
isVirtualAstroFilePath,
ensureRealAstroFilePath,
getExtensionFromScriptKind
} from './utils';
import { createAstroSys } from './astro-sys'; import { createAstroSys } from './astro-sys';
/** /**
* Caches resolved modules. * Caches resolved modules.
*/ */
class ModuleResolutionCache { class ModuleResolutionCache {
private cache = new Map<string, ts.ResolvedModule>(); private cache = new Map<string, ts.ResolvedModule>();
/** /**
* Tries to get a cached module. * Tries to get a cached module.
*/ */
get(moduleName: string, containingFile: string): ts.ResolvedModule | undefined { get(moduleName: string, containingFile: string): ts.ResolvedModule | undefined {
return this.cache.get(this.getKey(moduleName, containingFile)); return this.cache.get(this.getKey(moduleName, containingFile));
} }
/** /**
* Caches resolved module, if it is not undefined. * Caches resolved module, if it is not undefined.
*/ */
set(moduleName: string, containingFile: string, resolvedModule: ts.ResolvedModule | undefined) { set(moduleName: string, containingFile: string, resolvedModule: ts.ResolvedModule | undefined) {
if (!resolvedModule) { if (!resolvedModule) {
return; return;
}
this.cache.set(this.getKey(moduleName, containingFile), resolvedModule);
} }
this.cache.set(this.getKey(moduleName, containingFile), resolvedModule);
}
/** /**
* Deletes module from cache. Call this if a file was deleted. * Deletes module from cache. Call this if a file was deleted.
* @param resolvedModuleName full path of the module * @param resolvedModuleName full path of the module
*/ */
delete(resolvedModuleName: string): void { delete(resolvedModuleName: string): void {
this.cache.forEach((val, key) => { this.cache.forEach((val, key) => {
if (val.resolvedFileName === resolvedModuleName) { if (val.resolvedFileName === resolvedModuleName) {
this.cache.delete(key); this.cache.delete(key);
} }
}); });
} }
private getKey(moduleName: string, containingFile: string) { private getKey(moduleName: string, containingFile: string) {
return containingFile + ':::' + ensureRealAstroFilePath(moduleName); return containingFile + ':::' + ensureRealAstroFilePath(moduleName);
} }
} }
/** /**
@ -59,74 +55,56 @@ class ModuleResolutionCache {
* @param getSnapshot A function which returns a (in case of astro file fully preprocessed) typescript/javascript snapshot * @param getSnapshot A function which returns a (in case of astro file fully preprocessed) typescript/javascript snapshot
* @param compilerOptions The typescript compiler options * @param compilerOptions The typescript compiler options
*/ */
export function createAstroModuleLoader( export function createAstroModuleLoader(getSnapshot: (fileName: string) => DocumentSnapshot, compilerOptions: ts.CompilerOptions) {
getSnapshot: (fileName: string) => DocumentSnapshot, const astroSys = createAstroSys(getSnapshot);
compilerOptions: ts.CompilerOptions const moduleCache = new ModuleResolutionCache();
) {
const astroSys = createAstroSys(getSnapshot);
const moduleCache = new ModuleResolutionCache();
return { return {
fileExists: astroSys.fileExists, fileExists: astroSys.fileExists,
readFile: astroSys.readFile, readFile: astroSys.readFile,
writeFile: astroSys.writeFile, writeFile: astroSys.writeFile,
readDirectory: astroSys.readDirectory, readDirectory: astroSys.readDirectory,
directoryExists: astroSys.directoryExists, directoryExists: astroSys.directoryExists,
getDirectories: astroSys.getDirectories, getDirectories: astroSys.getDirectories,
realpath: astroSys.realpath, realpath: astroSys.realpath,
deleteFromModuleCache: (path: string) => moduleCache.delete(path), deleteFromModuleCache: (path: string) => moduleCache.delete(path),
resolveModuleNames resolveModuleNames,
};
function resolveModuleNames(moduleNames: string[], containingFile: string): Array<ts.ResolvedModule | undefined> {
return moduleNames.map((moduleName) => {
const cachedModule = moduleCache.get(moduleName, containingFile);
if (cachedModule) {
return cachedModule;
}
const resolvedModule = resolveModuleName(moduleName, containingFile);
moduleCache.set(moduleName, containingFile, resolvedModule);
return resolvedModule;
});
}
function resolveModuleName(name: string, containingFile: string): ts.ResolvedModule | undefined {
// Delegate to the TS resolver first.
// If that does not bring up anything, try the Astro Module loader
// which is able to deal with .astro files.
const tsResolvedModule = ts.resolveModuleName(name, containingFile, compilerOptions, ts.sys).resolvedModule;
if (tsResolvedModule && !isVirtualAstroFilePath(tsResolvedModule.resolvedFileName)) {
return tsResolvedModule;
}
const astroResolvedModule = ts.resolveModuleName(name, containingFile, compilerOptions, astroSys).resolvedModule;
if (!astroResolvedModule || !isVirtualAstroFilePath(astroResolvedModule.resolvedFileName)) {
return astroResolvedModule;
}
const resolvedFileName = ensureRealAstroFilePath(astroResolvedModule.resolvedFileName);
const snapshot = getSnapshot(resolvedFileName);
const resolvedastroModule: ts.ResolvedModuleFull = {
extension: getExtensionFromScriptKind(snapshot && snapshot.scriptKind),
resolvedFileName,
}; };
return resolvedastroModule;
function resolveModuleNames( }
moduleNames: string[],
containingFile: string
): Array<ts.ResolvedModule | undefined> {
return moduleNames.map((moduleName) => {
const cachedModule = moduleCache.get(moduleName, containingFile);
if (cachedModule) {
return cachedModule;
}
const resolvedModule = resolveModuleName(moduleName, containingFile);
moduleCache.set(moduleName, containingFile, resolvedModule);
return resolvedModule;
});
}
function resolveModuleName(
name: string,
containingFile: string
): ts.ResolvedModule | undefined {
// Delegate to the TS resolver first.
// If that does not bring up anything, try the Astro Module loader
// which is able to deal with .astro files.
const tsResolvedModule = ts.resolveModuleName(name, containingFile, compilerOptions, ts.sys)
.resolvedModule;
if (tsResolvedModule && !isVirtualAstroFilePath(tsResolvedModule.resolvedFileName)) {
return tsResolvedModule;
}
const astroResolvedModule = ts.resolveModuleName(
name,
containingFile,
compilerOptions,
astroSys
).resolvedModule;
if (
!astroResolvedModule ||
!isVirtualAstroFilePath(astroResolvedModule.resolvedFileName)
) {
return astroResolvedModule;
}
const resolvedFileName = ensureRealAstroFilePath(astroResolvedModule.resolvedFileName);
const snapshot = getSnapshot(resolvedFileName);
const resolvedastroModule: ts.ResolvedModuleFull = {
extension: getExtensionFromScriptKind(snapshot && snapshot.scriptKind),
resolvedFileName
};
return resolvedastroModule;
}
} }

View file

@ -113,17 +113,17 @@ export function getScriptKindFromFileName(fileName: string): ts.ScriptKind {
export function getExtensionFromScriptKind(kind: ts.ScriptKind | undefined): ts.Extension { export function getExtensionFromScriptKind(kind: ts.ScriptKind | undefined): ts.Extension {
switch (kind) { switch (kind) {
case ts.ScriptKind.JSX: case ts.ScriptKind.JSX:
return ts.Extension.Jsx; return ts.Extension.Jsx;
case ts.ScriptKind.TS: case ts.ScriptKind.TS:
return ts.Extension.Ts; return ts.Extension.Ts;
case ts.ScriptKind.TSX: case ts.ScriptKind.TSX:
return ts.Extension.Tsx; return ts.Extension.Tsx;
case ts.ScriptKind.JSON: case ts.ScriptKind.JSON:
return ts.Extension.Json; return ts.Extension.Json;
case ts.ScriptKind.JS: case ts.ScriptKind.JS:
default: default:
return ts.Extension.Js; return ts.Extension.Js;
} }
} }

View file

@ -15,6 +15,6 @@ To start the development server run:
yarn dev:vscode yarn dev:vscode
``` ```
Then in the __Debug__ panel select __Launch Extension__ from the dropdown and click the run button. Then in the **Debug** panel select **Launch Extension** from the dropdown and click the run button.
<img width="558" alt="Screen Shot 2021-05-07 at 8 51 37 AM" src="https://user-images.githubusercontent.com/361671/117452223-807e5580-af11-11eb-8404-dd615784408a.png"> <img width="558" alt="Screen Shot 2021-05-07 at 8 51 37 AM" src="https://user-images.githubusercontent.com/361671/117452223-807e5580-af11-11eb-8404-dd615784408a.png">

View file

@ -53,16 +53,19 @@ function createLanguageService(context: vscode.ExtensionContext, mode: 'doc', id
context.subscriptions.push(client.start()); context.subscriptions.push(client.start());
client.onReady().then(() => { client
const tagRequestor = (document: vscode.TextDocument, position: vscode.Position) => { .onReady()
const param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position); .then(() => {
return client.sendRequest(TagCloseRequest, param); const tagRequestor = (document: vscode.TextDocument, position: vscode.Position) => {
}; const param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position);
const disposable = activateTagClosing(tagRequestor, { astro: true }, 'html.autoClosingTags'); return client.sendRequest(TagCloseRequest, param);
context.subscriptions.push(disposable); };
}).catch(err => { const disposable = activateTagClosing(tagRequestor, { astro: true }, 'html.autoClosingTags');
console.error('Astro, unable to load language server.', err); context.subscriptions.push(disposable);
}); })
.catch((err) => {
console.error('Astro, unable to load language server.', err);
});
return client; return client;
} }

View file

@ -300,7 +300,7 @@
"@changesets/cli@^2.16.0": "@changesets/cli@^2.16.0":
version "2.16.0" version "2.16.0"
resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.16.0.tgz" resolved "https://registry.yarnpkg.com/@changesets/cli/-/cli-2.16.0.tgz#9f794005d0503efba5e348b929821a1732fd0f0d"
integrity sha512-VFkXSyyk/WRjjUoBI7g7cDy09qBjPbBQOloPMEshTzMo/NY9muWHl2yB/FSSkV/6PxGimPtJ7aEJPYfk8HCfXw== integrity sha512-VFkXSyyk/WRjjUoBI7g7cDy09qBjPbBQOloPMEshTzMo/NY9muWHl2yB/FSSkV/6PxGimPtJ7aEJPYfk8HCfXw==
dependencies: dependencies:
"@babel/runtime" "^7.10.4" "@babel/runtime" "^7.10.4"
@ -11402,7 +11402,7 @@ typedarray@^0.0.6:
typescript@^4.2.4: typescript@^4.2.4:
version "4.2.4" version "4.2.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
ua-parser-js@^0.7.18: ua-parser-js@^0.7.18: